]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
import unmodified lib/isc from ISC bind-9.6.1-P1.tar.gz
authorDave Hart <hart@ntp.org>
Thu, 24 Sep 2009 15:52:46 +0000 (15:52 +0000)
committerDave Hart <hart@ntp.org>
Thu, 24 Sep 2009 15:52:46 +0000 (15:52 +0000)
bk: 4abb95cexy7jFQ5B_Vz8c3pjE-VeVw

239 files changed:
lib/isc/alpha/include/isc/atomic.h [new file with mode: 0644]
lib/isc/api [new file with mode: 0644]
lib/isc/assertions.c
lib/isc/base32.c [new file with mode: 0644]
lib/isc/base64.c [new file with mode: 0644]
lib/isc/bitstring.c [new file with mode: 0644]
lib/isc/buffer.c [new file with mode: 0644]
lib/isc/bufferlist.c [new file with mode: 0644]
lib/isc/commandline.c [new file with mode: 0644]
lib/isc/entropy.c [new file with mode: 0644]
lib/isc/error.c
lib/isc/event.c [new file with mode: 0644]
lib/isc/fsaccess.c [new file with mode: 0644]
lib/isc/hash.c [new file with mode: 0644]
lib/isc/heap.c [new file with mode: 0644]
lib/isc/hex.c [new file with mode: 0644]
lib/isc/hmacmd5.c [new file with mode: 0644]
lib/isc/hmacsha.c [new file with mode: 0644]
lib/isc/httpd.c [new file with mode: 0644]
lib/isc/ia64/include/isc/atomic.h [new file with mode: 0644]
lib/isc/include/isc/app.h
lib/isc/include/isc/assertions.h
lib/isc/include/isc/base32.h [new file with mode: 0644]
lib/isc/include/isc/base64.h [new file with mode: 0644]
lib/isc/include/isc/bitstring.h [new file with mode: 0644]
lib/isc/include/isc/boolean.h
lib/isc/include/isc/buffer.h
lib/isc/include/isc/bufferlist.h [new file with mode: 0644]
lib/isc/include/isc/commandline.h [new file with mode: 0644]
lib/isc/include/isc/entropy.h [new file with mode: 0644]
lib/isc/include/isc/error.h
lib/isc/include/isc/event.h [new file with mode: 0644]
lib/isc/include/isc/eventclass.h [new file with mode: 0644]
lib/isc/include/isc/file.h
lib/isc/include/isc/formatcheck.h
lib/isc/include/isc/fsaccess.h [new file with mode: 0644]
lib/isc/include/isc/hash.h [new file with mode: 0644]
lib/isc/include/isc/heap.h [new file with mode: 0644]
lib/isc/include/isc/hex.h [new file with mode: 0644]
lib/isc/include/isc/hmacmd5.h [new file with mode: 0644]
lib/isc/include/isc/hmacsha.h [new file with mode: 0644]
lib/isc/include/isc/httpd.h [new file with mode: 0644]
lib/isc/include/isc/interfaceiter.h
lib/isc/include/isc/ipv6.h
lib/isc/include/isc/iterated_hash.h [new file with mode: 0644]
lib/isc/include/isc/lang.h
lib/isc/include/isc/lex.h [new file with mode: 0644]
lib/isc/include/isc/lfsr.h [new file with mode: 0644]
lib/isc/include/isc/lib.h
lib/isc/include/isc/list.h
lib/isc/include/isc/log.h
lib/isc/include/isc/magic.h
lib/isc/include/isc/mem.h
lib/isc/include/isc/msgcat.h
lib/isc/include/isc/msgs.h
lib/isc/include/isc/mutexblock.h [new file with mode: 0644]
lib/isc/include/isc/netaddr.h
lib/isc/include/isc/netscope.h
lib/isc/include/isc/ondestroy.h [new file with mode: 0644]
lib/isc/include/isc/os.h [new file with mode: 0644]
lib/isc/include/isc/parseint.h [new file with mode: 0644]
lib/isc/include/isc/platform.h.in [new file with mode: 0644]
lib/isc/include/isc/portset.h [new file with mode: 0644]
lib/isc/include/isc/print.h
lib/isc/include/isc/quota.h [new file with mode: 0644]
lib/isc/include/isc/radix.h [new file with mode: 0644]
lib/isc/include/isc/random.h [new file with mode: 0644]
lib/isc/include/isc/ratelimiter.h [new file with mode: 0644]
lib/isc/include/isc/refcount.h [new file with mode: 0644]
lib/isc/include/isc/region.h
lib/isc/include/isc/resource.h [new file with mode: 0644]
lib/isc/include/isc/result.h
lib/isc/include/isc/resultclass.h [new file with mode: 0644]
lib/isc/include/isc/rwlock.h [new file with mode: 0644]
lib/isc/include/isc/serial.h [new file with mode: 0644]
lib/isc/include/isc/sha1.h [new file with mode: 0644]
lib/isc/include/isc/sha2.h [new file with mode: 0644]
lib/isc/include/isc/sockaddr.h
lib/isc/include/isc/socket.h [new file with mode: 0644]
lib/isc/include/isc/stats.h [new file with mode: 0644]
lib/isc/include/isc/stdio.h
lib/isc/include/isc/stdlib.h [new file with mode: 0644]
lib/isc/include/isc/string.h
lib/isc/include/isc/symtab.h [new file with mode: 0644]
lib/isc/include/isc/task.h [new file with mode: 0644]
lib/isc/include/isc/taskpool.h [new file with mode: 0644]
lib/isc/include/isc/timer.h [new file with mode: 0644]
lib/isc/include/isc/types.h
lib/isc/include/isc/util.h
lib/isc/include/isc/version.h [new file with mode: 0644]
lib/isc/include/isc/xml.h [new file with mode: 0644]
lib/isc/inet_aton.c
lib/isc/inet_ntop.c
lib/isc/inet_pton.c
lib/isc/iterated_hash.c [new file with mode: 0644]
lib/isc/lex.c [new file with mode: 0644]
lib/isc/lfsr.c [new file with mode: 0644]
lib/isc/lib.c
lib/isc/log.c
lib/isc/mem.c
lib/isc/mips/include/isc/atomic.h [new file with mode: 0644]
lib/isc/mutexblock.c [new file with mode: 0644]
lib/isc/netaddr.c
lib/isc/netscope.c
lib/isc/nls/msgcat.c
lib/isc/noatomic/include/isc/atomic.h [new file with mode: 0644]
lib/isc/nothreads/condition.c [new file with mode: 0644]
lib/isc/nothreads/include/isc/condition.h [new file with mode: 0644]
lib/isc/nothreads/include/isc/mutex.h [new file with mode: 0644]
lib/isc/nothreads/include/isc/once.h [new file with mode: 0644]
lib/isc/nothreads/include/isc/thread.h [new file with mode: 0644]
lib/isc/nothreads/mutex.c [new file with mode: 0644]
lib/isc/nothreads/thread.c [new file with mode: 0644]
lib/isc/ondestroy.c [new file with mode: 0644]
lib/isc/parseint.c [new file with mode: 0644]
lib/isc/portset.c [new file with mode: 0644]
lib/isc/powerpc/include/isc/atomic.h [new file with mode: 0644]
lib/isc/print.c [new file with mode: 0644]
lib/isc/pthreads/condition.c [new file with mode: 0644]
lib/isc/pthreads/include/isc/condition.h [new file with mode: 0644]
lib/isc/pthreads/include/isc/mutex.h [new file with mode: 0644]
lib/isc/pthreads/include/isc/once.h [new file with mode: 0644]
lib/isc/pthreads/include/isc/thread.h [new file with mode: 0644]
lib/isc/pthreads/mutex.c [new file with mode: 0644]
lib/isc/pthreads/thread.c [new file with mode: 0644]
lib/isc/quota.c [new file with mode: 0644]
lib/isc/radix.c [new file with mode: 0644]
lib/isc/random.c [new file with mode: 0644]
lib/isc/ratelimiter.c [new file with mode: 0644]
lib/isc/refcount.c [new file with mode: 0644]
lib/isc/region.c [new file with mode: 0644]
lib/isc/result.c [new file with mode: 0644]
lib/isc/rwlock.c [new file with mode: 0644]
lib/isc/serial.c [new file with mode: 0644]
lib/isc/sha1.c [new file with mode: 0644]
lib/isc/sha2.c [new file with mode: 0644]
lib/isc/sockaddr.c
lib/isc/sparc64/include/isc/atomic.h [new file with mode: 0644]
lib/isc/stats.c [new file with mode: 0644]
lib/isc/string.c [new file with mode: 0644]
lib/isc/strtoul.c [new file with mode: 0644]
lib/isc/symtab.c [new file with mode: 0644]
lib/isc/task.c [new file with mode: 0644]
lib/isc/task_p.h [new file with mode: 0644]
lib/isc/taskpool.c [new file with mode: 0644]
lib/isc/timer.c [new file with mode: 0644]
lib/isc/timer_p.h [new file with mode: 0644]
lib/isc/unix/app.c [new file with mode: 0644]
lib/isc/unix/dir.c [new file with mode: 0644]
lib/isc/unix/entropy.c [new file with mode: 0644]
lib/isc/unix/errno2result.c [new file with mode: 0644]
lib/isc/unix/errno2result.h [new file with mode: 0644]
lib/isc/unix/file.c [new file with mode: 0644]
lib/isc/unix/fsaccess.c [new file with mode: 0644]
lib/isc/unix/ifiter_getifaddrs.c
lib/isc/unix/ifiter_ioctl.c
lib/isc/unix/ifiter_sysctl.c
lib/isc/unix/include/isc/dir.h
lib/isc/unix/include/isc/int.h
lib/isc/unix/include/isc/keyboard.h [new file with mode: 0644]
lib/isc/unix/include/isc/net.h
lib/isc/unix/include/isc/netdb.h [new file with mode: 0644]
lib/isc/unix/include/isc/offset.h
lib/isc/unix/include/isc/stat.h
lib/isc/unix/include/isc/stdtime.h [new file with mode: 0644]
lib/isc/unix/include/isc/strerror.h
lib/isc/unix/include/isc/syslog.h [new file with mode: 0644]
lib/isc/unix/include/isc/time.h
lib/isc/unix/interfaceiter.c
lib/isc/unix/ipv6.c [new file with mode: 0644]
lib/isc/unix/keyboard.c [new file with mode: 0644]
lib/isc/unix/net.c
lib/isc/unix/os.c [new file with mode: 0644]
lib/isc/unix/resource.c [new file with mode: 0644]
lib/isc/unix/socket.c [new file with mode: 0644]
lib/isc/unix/socket_p.h [new file with mode: 0644]
lib/isc/unix/stdio.c [new file with mode: 0644]
lib/isc/unix/stdtime.c [new file with mode: 0644]
lib/isc/unix/strerror.c
lib/isc/unix/syslog.c [new file with mode: 0644]
lib/isc/unix/time.c [new file with mode: 0644]
lib/isc/version.c [new file with mode: 0644]
lib/isc/win32/DLLMain.c [new file with mode: 0644]
lib/isc/win32/app.c [new file with mode: 0644]
lib/isc/win32/condition.c [new file with mode: 0644]
lib/isc/win32/dir.c [new file with mode: 0644]
lib/isc/win32/entropy.c [new file with mode: 0644]
lib/isc/win32/errno2result.c [new file with mode: 0644]
lib/isc/win32/errno2result.h [new file with mode: 0644]
lib/isc/win32/file.c [new file with mode: 0644]
lib/isc/win32/fsaccess.c [new file with mode: 0644]
lib/isc/win32/include/isc/bind_registry.h [new file with mode: 0644]
lib/isc/win32/include/isc/bindevt.h [new file with mode: 0644]
lib/isc/win32/include/isc/condition.h [new file with mode: 0644]
lib/isc/win32/include/isc/dir.h [new file with mode: 0644]
lib/isc/win32/include/isc/int.h
lib/isc/win32/include/isc/ipv6.h
lib/isc/win32/include/isc/keyboard.h [new file with mode: 0644]
lib/isc/win32/include/isc/mutex.h
lib/isc/win32/include/isc/netdb.h [new file with mode: 0644]
lib/isc/win32/include/isc/ntgroups.h [new file with mode: 0644]
lib/isc/win32/include/isc/ntpaths.h [new file with mode: 0644]
lib/isc/win32/include/isc/offset.h
lib/isc/win32/include/isc/once.h
lib/isc/win32/include/isc/platform.h
lib/isc/win32/include/isc/stat.h
lib/isc/win32/include/isc/stdtime.h [new file with mode: 0644]
lib/isc/win32/include/isc/strerror.h
lib/isc/win32/include/isc/syslog.h [new file with mode: 0644]
lib/isc/win32/include/isc/thread.h [new file with mode: 0644]
lib/isc/win32/include/isc/time.h [new file with mode: 0644]
lib/isc/win32/include/isc/win32os.h
lib/isc/win32/interfaceiter.c
lib/isc/win32/ipv6.c [new file with mode: 0644]
lib/isc/win32/keyboard.c [new file with mode: 0644]
lib/isc/win32/libisc.def [new file with mode: 0644]
lib/isc/win32/libisc.dsp [new file with mode: 0644]
lib/isc/win32/libisc.dsw [new file with mode: 0644]
lib/isc/win32/libisc.mak [new file with mode: 0644]
lib/isc/win32/net.c
lib/isc/win32/netdb.h [new file with mode: 0644]
lib/isc/win32/ntgroups.c [new file with mode: 0644]
lib/isc/win32/ntpaths.c [new file with mode: 0644]
lib/isc/win32/once.c
lib/isc/win32/os.c [new file with mode: 0644]
lib/isc/win32/resource.c [new file with mode: 0644]
lib/isc/win32/socket.c [new file with mode: 0644]
lib/isc/win32/stdio.c [new file with mode: 0644]
lib/isc/win32/stdtime.c [new file with mode: 0644]
lib/isc/win32/strerror.c
lib/isc/win32/syslog.c [new file with mode: 0644]
lib/isc/win32/syslog.h [new file with mode: 0644]
lib/isc/win32/thread.c [new file with mode: 0644]
lib/isc/win32/time.c [new file with mode: 0644]
lib/isc/win32/unistd.h [new file with mode: 0644]
lib/isc/win32/version.c [new file with mode: 0644]
lib/isc/win32/win32os.c
lib/isc/x86_32/include/isc/atomic.h [new file with mode: 0644]
lib/isc/x86_64/include/isc/atomic.h [new file with mode: 0644]

diff --git a/lib/isc/alpha/include/isc/atomic.h b/lib/isc/alpha/include/isc/atomic.h
new file mode 100644 (file)
index 0000000..bc1510f
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.5.332.2 2009/04/08 06:47:32 tbox Exp $ */
+
+/*
+ * This code was written based on FreeBSD's kernel source whose copyright
+ * follows:
+ */
+
+/*-
+ * Copyright (c) 1998 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/alpha/include/atomic.h,v 1.18.6.1 2004/09/13 21:52:04 wilko Exp $
+ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEOSFASM
+#include <c_asm.h>
+
+#pragma intrinsic(asm)
+
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.  Memory access ordering around this function
+ * can be critical, so we add explicit memory block instructions at the
+ * beginning and the end of it (same for other functions).
+ */
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+       return (asm("mb;"
+                   "1:"
+                   "ldl_l %t0, 0(%a0);"        /* load old value */
+                   "mov %t0, %v0;"             /* copy the old value */
+                   "addl %t0, %a1, %t0;"       /* calculate new value */
+                   "stl_c %t0, 0(%a0);"        /* attempt to store */
+                   "beq %t0, 1b;"              /* spin if failed */
+                   "mb;",
+                   p, val));
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+       (void)asm("mb;"
+                 "1:"
+                 "ldl_l %t0, 0(%a0);"          /* load old value */
+                 "mov %a1, %t0;"               /* value to store */
+                 "stl_c %t0, 0(%a0);"          /* attempt to store */
+                 "beq %t0, 1b;"                /* spin if failed */
+                 "mb;",
+                 p, val);
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'.  The original value is returned in any
+ * case.
+ */
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+
+       return(asm("mb;"
+                  "1:"
+                  "ldl_l %t0, 0(%a0);"         /* load old value */
+                  "mov %t0, %v0;"              /* copy the old value */
+                  "cmpeq %t0, %a1, %t0;"       /* compare */
+                  "beq %t0, 2f;"               /* exit if not equal */
+                  "mov %a2, %t0;"              /* value to store */
+                  "stl_c %t0, 0(%a0);"         /* attempt to store */
+                  "beq %t0, 1b;"               /* if it failed, spin */
+                  "2:"
+                  "mb;",
+                  p, cmpval, val));
+}
+#elif defined (ISC_PLATFORM_USEGCCASM)
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+       isc_int32_t temp, prev;
+
+       __asm__ volatile(
+               "mb;"
+               "1:"
+               "ldl_l %0, %1;"                 /* load old value */
+               "mov %0, %2;"                   /* copy the old value */
+               "addl %0, %3, %0;"              /* calculate new value */
+               "stl_c %0, %1;"                 /* attempt to store */
+               "beq %0, 1b;"                   /* spin if failed */
+               "mb;"
+               : "=&r"(temp), "+m"(*p), "=&r"(prev)
+               : "r"(val)
+               : "memory");
+
+       return (prev);
+}
+
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+       isc_int32_t temp;
+
+       __asm__ volatile(
+               "mb;"
+               "1:"
+               "ldl_l %0, %1;"                 /* load old value */
+               "mov %2, %0;"                   /* value to store */
+               "stl_c %0, %1;"                 /* attempt to store */
+               "beq %0, 1b;"                   /* if it failed, spin */
+               "mb;"
+               : "=&r"(temp), "+m"(*p)
+               : "r"(val)
+               : "memory");
+}
+
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+       isc_int32_t temp, prev;
+
+       __asm__ volatile(
+               "mb;"
+               "1:"
+               "ldl_l %0, %1;"                 /* load old value */
+               "mov %0, %2;"                   /* copy the old value */
+               "cmpeq %0, %3, %0;"             /* compare */
+               "beq %0, 2f;"                   /* exit if not equal */
+               "mov %4, %0;"                   /* value to store */
+               "stl_c %0, %1;"                 /* attempt to store */
+               "beq %0, 1b;"                   /* if it failed, spin */
+               "2:"
+               "mb;"
+               : "=&r"(temp), "+m"(*p), "=&r"(prev)
+               : "r"(cmpval), "r"(val)
+               : "memory");
+
+       return (prev);
+}
+#else
+
+#error "unsupported compiler.  disable atomic ops by --disable-atomic"
+
+#endif
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/api b/lib/isc/api
new file mode 100644 (file)
index 0000000..5ef8dc0
--- /dev/null
@@ -0,0 +1,3 @@
+LIBINTERFACE = 51
+LIBREVISION = 1
+LIBAGE = 1
index 08dd5f3d51f7651c3c4ba1ec3fb2034f35739b69..4c9251bdcf25199dd622049ae35821775caf842d 100644 (file)
@@ -1,21 +1,23 @@
 /*
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1997-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: assertions.c,v 1.16 2001/07/16 03:52:05 mayer Exp $ */
+/* $Id: assertions.c,v 1.23 2008/10/15 23:47:31 tbox Exp $ */
+
+/*! \file */
 
 #include <config.h>
 
 #include <isc/assertions.h>
 #include <isc/msgs.h>
 
-/*
+/*%
  * Forward.
  */
-
+/* coverity[+kill] */
 static void
 default_callback(const char *, int, isc_assertiontype_t, const char *);
 
-/*
+/*%
  * Public.
  */
 
 LIBISC_EXTERNAL_DATA isc_assertioncallback_t isc_assertion_failed =
                                             default_callback;
 
+/*% Set callback. */
 void
 isc_assertion_setcallback(isc_assertioncallback_t cb) {
        if (cb == NULL)
@@ -47,6 +50,7 @@ isc_assertion_setcallback(isc_assertioncallback_t cb) {
                isc_assertion_failed = cb;
 }
 
+/*% Type to Text */
 const char *
 isc_assertion_typetotext(isc_assertiontype_t type) {
        const char *result;
diff --git a/lib/isc/base32.c b/lib/isc/base32.c
new file mode 100644 (file)
index 0000000..3000a84
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2008, 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: base32.c,v 1.3.116.2 2009/01/18 23:47:41 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/base32.h>
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define RETERR(x) do { \
+       isc_result_t _r = (x); \
+       if (_r != ISC_R_SUCCESS) \
+               return (_r); \
+       } while (0)
+
+
+/*@{*/
+/*!
+ * These static functions are also present in lib/dns/rdata.c.  I'm not
+ * sure where they should go. -- bwelling
+ */
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target);
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
+
+/*@}*/
+
+static const char base32[] =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=abcdefghijklmnopqrstuvwxyz234567";
+static const char base32hex[] =
+       "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
+
+static isc_result_t
+base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
+             isc_buffer_t *target, const char base[])
+{
+       char buf[9];
+       unsigned int loops = 0;
+
+       if (wordlength >= 0 && wordlength < 8)
+               wordlength = 8;
+
+       memset(buf, 0, sizeof(buf));
+       while (source->length > 0) {
+               buf[0] = base[((source->base[0]>>3)&0x1f)];     /* 5 + */
+               if (source->length == 1) {
+                       buf[1] = base[(source->base[0]<<2)&0x1c];
+                       buf[2] = buf[3] = buf[4] = '=';
+                       buf[5] = buf[6] = buf[7] = '=';
+                       RETERR(str_totext(buf, target));
+                       break;
+               }
+               buf[1] = base[((source->base[0]<<2)&0x1c)|      /* 3 = 8 */
+                             ((source->base[1]>>6)&0x03)];     /* 2 + */
+               buf[2] = base[((source->base[1]>>1)&0x1f)];     /* 5 + */
+               if (source->length == 2) {
+                       buf[3] = base[(source->base[1]<<4)&0x10];
+                       buf[4] = buf[5] = buf[6] = buf[7] = '=';
+                       RETERR(str_totext(buf, target));
+                       break;
+               }
+               buf[3] = base[((source->base[1]<<4)&0x10)|      /* 1 = 8 */
+                             ((source->base[2]>>4)&0x0f)];     /* 4 + */
+               if (source->length == 3) {
+                       buf[4] = base[(source->base[2]<<1)&0x1e];
+                       buf[5] = buf[6] = buf[7] = '=';
+                       RETERR(str_totext(buf, target));
+                       break;
+               }
+               buf[4] = base[((source->base[2]<<1)&0x1e)|      /* 4 = 8 */
+                             ((source->base[3]>>7)&0x01)];     /* 1 + */
+               buf[5] = base[((source->base[3]>>2)&0x1f)];     /* 5 + */
+               if (source->length == 4) {
+                       buf[6] = base[(source->base[3]<<3)&0x18];
+                       buf[7] = '=';
+                       RETERR(str_totext(buf, target));
+                       break;
+               }
+               buf[6] = base[((source->base[3]<<3)&0x18)|      /* 2 = 8 */
+                             ((source->base[4]>>5)&0x07)];     /* 3 + */
+               buf[7] = base[source->base[4]&0x1f];            /* 5 = 8 */
+               RETERR(str_totext(buf, target));
+               isc_region_consume(source, 5);
+
+               loops++;
+               if (source->length != 0 && wordlength >= 0 &&
+                   (int)((loops + 1) * 8) >= wordlength)
+               {
+                       loops = 0;
+                       RETERR(str_totext(wordbreak, target));
+               }
+       }
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base32_totext(isc_region_t *source, int wordlength,
+                 const char *wordbreak, isc_buffer_t *target)
+{
+       return (base32_totext(source, wordlength, wordbreak, target, base32));
+}
+
+isc_result_t
+isc_base32hex_totext(isc_region_t *source, int wordlength,
+                    const char *wordbreak, isc_buffer_t *target)
+{
+       return (base32_totext(source, wordlength, wordbreak, target,
+                             base32hex));
+}
+
+/*%
+ * State of a base32 decoding process in progress.
+ */
+typedef struct {
+       int length;             /*%< Desired length of binary data or -1 */
+       isc_buffer_t *target;   /*%< Buffer for resulting binary data */
+       int digits;             /*%< Number of buffered base32 digits */
+       isc_boolean_t seen_end; /*%< True if "=" end marker seen */
+       int val[8];
+       const char *base;       /*%< Which encoding we are using */
+       int seen_32;            /*%< Number of significant bytes if non zero */
+} base32_decode_ctx_t;
+
+static inline void
+base32_decode_init(base32_decode_ctx_t *ctx, int length,
+                  const char base[], isc_buffer_t *target)
+{
+       ctx->digits = 0;
+       ctx->seen_end = ISC_FALSE;
+       ctx->seen_32 = 0;
+       ctx->length = length;
+       ctx->target = target;
+       ctx->base = base;
+}
+
+static inline isc_result_t
+base32_decode_char(base32_decode_ctx_t *ctx, int c) {
+       char *s;
+       unsigned int last;
+
+       if (ctx->seen_end)
+               return (ISC_R_BADBASE32);
+       if ((s = strchr(ctx->base, c)) == NULL)
+               return (ISC_R_BADBASE32);
+       last = s - ctx->base;
+       /*
+        * Handle lower case.
+        */
+       if (last > 32)
+               last -= 33;
+       /*
+        * Check that padding is contiguous.
+        */
+       if (last != 32 && ctx->seen_32 != 0)
+               return (ISC_R_BADBASE32);
+       /*
+        * Check that padding starts at the right place and that
+        * bits that should be zero are.
+        * Record how many significant bytes in answer (seen_32).
+        */
+       if (last == 32 && ctx->seen_32 == 0)
+               switch (ctx->digits) {
+               case 0:
+               case 1:
+                       return (ISC_R_BADBASE32);
+               case 2:
+                       if ((ctx->val[1]&0x03) != 0)
+                               return (ISC_R_BADBASE32);
+                       ctx->seen_32 = 1;
+                       break;
+               case 3:
+                       return (ISC_R_BADBASE32);
+               case 4:
+                       if ((ctx->val[3]&0x0f) != 0)
+                               return (ISC_R_BADBASE32);
+                       ctx->seen_32 = 3;
+                       break;
+               case 5:
+                       if ((ctx->val[4]&0x01) != 0)
+                               return (ISC_R_BADBASE32);
+                       ctx->seen_32 = 3;
+                       break;
+               case 6:
+                       return (ISC_R_BADBASE32);
+               case 7:
+                       if ((ctx->val[6]&0x07) != 0)
+                               return (ISC_R_BADBASE32);
+                       ctx->seen_32 = 4;
+                       break;
+               }
+       /*
+        * Zero fill pad values.
+        */
+       ctx->val[ctx->digits++] = (last == 32) ? 0 : last;
+
+       if (ctx->digits == 8) {
+               int n = 5;
+               unsigned char buf[5];
+
+               if (ctx->seen_32 != 0) {
+                       ctx->seen_end = ISC_TRUE;
+                       n = ctx->seen_32;
+               }
+               buf[0] = (ctx->val[0]<<3)|(ctx->val[1]>>2);
+               buf[1] = (ctx->val[1]<<6)|(ctx->val[2]<<1)|(ctx->val[3]>>4);
+               buf[2] = (ctx->val[3]<<4)|(ctx->val[4]>>1);
+               buf[3] = (ctx->val[4]<<7)|(ctx->val[5]<<2)|(ctx->val[6]>>3);
+               buf[4] = (ctx->val[6]<<5)|(ctx->val[7]);
+               RETERR(mem_tobuffer(ctx->target, buf, n));
+               if (ctx->length >= 0) {
+                       if (n > ctx->length)
+                               return (ISC_R_BADBASE32);
+                       else
+                               ctx->length -= n;
+               }
+               ctx->digits = 0;
+       }
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+base32_decode_finish(base32_decode_ctx_t *ctx) {
+       if (ctx->length > 0)
+               return (ISC_R_UNEXPECTEDEND);
+       if (ctx->digits != 0)
+               return (ISC_R_BADBASE32);
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+base32_tobuffer(isc_lex_t *lexer, const char base[], isc_buffer_t *target,
+               int length)
+{
+       base32_decode_ctx_t ctx;
+       isc_textregion_t *tr;
+       isc_token_t token;
+       isc_boolean_t eol;
+
+       base32_decode_init(&ctx, length, base, target);
+
+       while (!ctx.seen_end && (ctx.length != 0)) {
+               unsigned int i;
+
+               if (length > 0)
+                       eol = ISC_FALSE;
+               else
+                       eol = ISC_TRUE;
+               RETERR(isc_lex_getmastertoken(lexer, &token,
+                                             isc_tokentype_string, eol));
+               if (token.type != isc_tokentype_string)
+                       break;
+               tr = &token.value.as_textregion;
+               for (i = 0; i < tr->length; i++)
+                       RETERR(base32_decode_char(&ctx, tr->base[i]));
+       }
+       if (ctx.length < 0 && !ctx.seen_end)
+               isc_lex_ungettoken(lexer, &token);
+       RETERR(base32_decode_finish(&ctx));
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+       return (base32_tobuffer(lexer, base32, target, length));
+}
+
+isc_result_t
+isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+       return (base32_tobuffer(lexer, base32hex, target, length));
+}
+
+static isc_result_t
+base32_decodestring(const char *cstr, const char base[], isc_buffer_t *target) {
+       base32_decode_ctx_t ctx;
+
+       base32_decode_init(&ctx, -1, base, target);
+       for (;;) {
+               int c = *cstr++;
+               if (c == '\0')
+                       break;
+               if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
+                       continue;
+               RETERR(base32_decode_char(&ctx, c));
+       }
+       RETERR(base32_decode_finish(&ctx));
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base32_decodestring(const char *cstr, isc_buffer_t *target) {
+       return (base32_decodestring(cstr, base32, target));
+}
+
+isc_result_t
+isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) {
+       return (base32_decodestring(cstr, base32hex, target));
+}
+
+static isc_result_t
+base32_decoderegion(isc_region_t *source, const char base[], isc_buffer_t *target) {
+       base32_decode_ctx_t ctx;
+
+       base32_decode_init(&ctx, -1, base, target);
+       while (source->length != 0) {
+               int c = *source->base;
+               RETERR(base32_decode_char(&ctx, c));
+               isc_region_consume(source, 1);
+       }
+       RETERR(base32_decode_finish(&ctx));
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) {
+       return (base32_decoderegion(source, base32, target));
+}
+
+isc_result_t
+isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) {
+       return (base32_decoderegion(source, base32hex, target));
+}
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+       unsigned int l;
+       isc_region_t region;
+
+       isc_buffer_availableregion(target, &region);
+       l = strlen(source);
+
+       if (l > region.length)
+               return (ISC_R_NOSPACE);
+
+       memcpy(region.base, source, l);
+       isc_buffer_add(target, l);
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
+       isc_region_t tr;
+
+       isc_buffer_availableregion(target, &tr);
+       if (length > tr.length)
+               return (ISC_R_NOSPACE);
+       memcpy(tr.base, base, length);
+       isc_buffer_add(target, length);
+       return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/base64.c b/lib/isc/base64.c
new file mode 100644 (file)
index 0000000..13ed6b5
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: base64.c,v 1.32 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/base64.h>
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define RETERR(x) do { \
+       isc_result_t _r = (x); \
+       if (_r != ISC_R_SUCCESS) \
+               return (_r); \
+       } while (0)
+
+
+/*@{*/
+/*!
+ * These static functions are also present in lib/dns/rdata.c.  I'm not
+ * sure where they should go. -- bwelling
+ */
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target);
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
+
+static const char base64[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+/*@}*/
+
+isc_result_t
+isc_base64_totext(isc_region_t *source, int wordlength,
+                 const char *wordbreak, isc_buffer_t *target)
+{
+       char buf[5];
+       unsigned int loops = 0;
+
+       if (wordlength < 4)
+               wordlength = 4;
+
+       memset(buf, 0, sizeof(buf));
+       while (source->length > 2) {
+               buf[0] = base64[(source->base[0]>>2)&0x3f];
+               buf[1] = base64[((source->base[0]<<4)&0x30)|
+                               ((source->base[1]>>4)&0x0f)];
+               buf[2] = base64[((source->base[1]<<2)&0x3c)|
+                               ((source->base[2]>>6)&0x03)];
+               buf[3] = base64[source->base[2]&0x3f];
+               RETERR(str_totext(buf, target));
+               isc_region_consume(source, 3);
+
+               loops++;
+               if (source->length != 0 &&
+                   (int)((loops + 1) * 4) >= wordlength)
+               {
+                       loops = 0;
+                       RETERR(str_totext(wordbreak, target));
+               }
+       }
+       if (source->length == 2) {
+               buf[0] = base64[(source->base[0]>>2)&0x3f];
+               buf[1] = base64[((source->base[0]<<4)&0x30)|
+                               ((source->base[1]>>4)&0x0f)];
+               buf[2] = base64[((source->base[1]<<2)&0x3c)];
+               buf[3] = '=';
+               RETERR(str_totext(buf, target));
+       } else if (source->length == 1) {
+               buf[0] = base64[(source->base[0]>>2)&0x3f];
+               buf[1] = base64[((source->base[0]<<4)&0x30)];
+               buf[2] = buf[3] = '=';
+               RETERR(str_totext(buf, target));
+       }
+       return (ISC_R_SUCCESS);
+}
+
+/*%
+ * State of a base64 decoding process in progress.
+ */
+typedef struct {
+       int length;             /*%< Desired length of binary data or -1 */
+       isc_buffer_t *target;   /*%< Buffer for resulting binary data */
+       int digits;             /*%< Number of buffered base64 digits */
+       isc_boolean_t seen_end; /*%< True if "=" end marker seen */
+       int val[4];
+} base64_decode_ctx_t;
+
+static inline void
+base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target)
+{
+       ctx->digits = 0;
+       ctx->seen_end = ISC_FALSE;
+       ctx->length = length;
+       ctx->target = target;
+}
+
+static inline isc_result_t
+base64_decode_char(base64_decode_ctx_t *ctx, int c) {
+       char *s;
+
+       if (ctx->seen_end)
+               return (ISC_R_BADBASE64);
+       if ((s = strchr(base64, c)) == NULL)
+               return (ISC_R_BADBASE64);
+       ctx->val[ctx->digits++] = s - base64;
+       if (ctx->digits == 4) {
+               int n;
+               unsigned char buf[3];
+               if (ctx->val[0] == 64 || ctx->val[1] == 64)
+                       return (ISC_R_BADBASE64);
+               if (ctx->val[2] == 64 && ctx->val[3] != 64)
+                       return (ISC_R_BADBASE64);
+               /*
+                * Check that bits that should be zero are.
+                */
+               if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0)
+                       return (ISC_R_BADBASE64);
+               /*
+                * We don't need to test for ctx->val[2] != 64 as
+                * the bottom two bits of 64 are zero.
+                */
+               if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0)
+                       return (ISC_R_BADBASE64);
+               n = (ctx->val[2] == 64) ? 1 :
+                       (ctx->val[3] == 64) ? 2 : 3;
+               if (n != 3) {
+                       ctx->seen_end = ISC_TRUE;
+                       if (ctx->val[2] == 64)
+                               ctx->val[2] = 0;
+                       if (ctx->val[3] == 64)
+                               ctx->val[3] = 0;
+               }
+               buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4);
+               buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2);
+               buf[2] = (ctx->val[2]<<6)|(ctx->val[3]);
+               RETERR(mem_tobuffer(ctx->target, buf, n));
+               if (ctx->length >= 0) {
+                       if (n > ctx->length)
+                               return (ISC_R_BADBASE64);
+                       else
+                               ctx->length -= n;
+               }
+               ctx->digits = 0;
+       }
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+base64_decode_finish(base64_decode_ctx_t *ctx) {
+       if (ctx->length > 0)
+               return (ISC_R_UNEXPECTEDEND);
+       if (ctx->digits != 0)
+               return (ISC_R_BADBASE64);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+       base64_decode_ctx_t ctx;
+       isc_textregion_t *tr;
+       isc_token_t token;
+       isc_boolean_t eol;
+
+       base64_decode_init(&ctx, length, target);
+
+       while (!ctx.seen_end && (ctx.length != 0)) {
+               unsigned int i;
+
+               if (length > 0)
+                       eol = ISC_FALSE;
+               else
+                       eol = ISC_TRUE;
+               RETERR(isc_lex_getmastertoken(lexer, &token,
+                                             isc_tokentype_string, eol));
+               if (token.type != isc_tokentype_string)
+                       break;
+               tr = &token.value.as_textregion;
+               for (i = 0; i < tr->length; i++)
+                       RETERR(base64_decode_char(&ctx, tr->base[i]));
+       }
+       if (ctx.length < 0 && !ctx.seen_end)
+               isc_lex_ungettoken(lexer, &token);
+       RETERR(base64_decode_finish(&ctx));
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_base64_decodestring(const char *cstr, isc_buffer_t *target) {
+       base64_decode_ctx_t ctx;
+
+       base64_decode_init(&ctx, -1, target);
+       for (;;) {
+               int c = *cstr++;
+               if (c == '\0')
+                       break;
+               if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
+                       continue;
+               RETERR(base64_decode_char(&ctx, c));
+       }
+       RETERR(base64_decode_finish(&ctx));     
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+       unsigned int l;
+       isc_region_t region;
+
+       isc_buffer_availableregion(target, &region);
+       l = strlen(source);
+
+       if (l > region.length)
+               return (ISC_R_NOSPACE);
+
+       memcpy(region.base, source, l);
+       isc_buffer_add(target, l);
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
+       isc_region_t tr;
+
+       isc_buffer_availableregion(target, &tr);
+       if (length > tr.length)
+               return (ISC_R_NOSPACE);
+       memcpy(tr.base, base, length);
+       isc_buffer_add(target, length);
+       return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/bitstring.c b/lib/isc/bitstring.c
new file mode 100644 (file)
index 0000000..33c7c1f
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: bitstring.c,v 1.17 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/magic.h>
+#include <isc/bitstring.h>
+#include <isc/util.h>
+
+#define DIV8(x)                        ((x) >> 3)
+#define MOD8(x)                        ((x) & 0x00000007U)
+#define OCTETS(n)              (((n) + 7) >> 3)
+#define PADDED(n)              ((((n) + 7) >> 3) << 3)
+#define BITSET(bs, n)          (((bs)->data[DIV8(n)] & \
+                                (1 << (7 - MOD8(n)))) != 0)
+#define SETBIT(bs, n)          (bs)->data[DIV8(n)] |= (1 << (7 - MOD8(n)))
+#define CLEARBIT(bs, n)                (bs)->data[DIV8(n)] &= ~(1 << (7 - MOD8(n)))
+
+#define BITSTRING_MAGIC                ISC_MAGIC('B', 'S', 't', 'r')
+#define VALID_BITSTRING(b)     ISC_MAGIC_VALID(b, BITSTRING_MAGIC)
+
+void
+isc_bitstring_init(isc_bitstring_t *bitstring, unsigned char *data,
+                  unsigned int length, unsigned int size, isc_boolean_t lsb0)
+{
+       /*
+        * Make 'bitstring' refer to the bitstring of 'size' bits starting
+        * at 'data'.  'length' bits of the bitstring are valid.  If 'lsb0'
+        * is set then, bit 0 refers to the least significant bit of the
+        * bitstring.  Otherwise bit 0 is the most significant bit.
+        */
+
+       REQUIRE(bitstring != NULL);
+       REQUIRE(data != NULL);
+       REQUIRE(length <= size);
+
+       bitstring->magic = BITSTRING_MAGIC;
+       bitstring->data = data;
+       bitstring->length = length;
+       bitstring->size = size;
+       bitstring->lsb0 = lsb0;
+}
+
+void
+isc_bitstring_invalidate(isc_bitstring_t *bitstring) {
+
+       /*
+        * Invalidate 'bitstring'.
+        */
+
+       REQUIRE(VALID_BITSTRING(bitstring));
+
+       bitstring->magic = 0;
+       bitstring->data = NULL;
+       bitstring->length = 0;
+       bitstring->size = 0;
+       bitstring->lsb0 = ISC_FALSE;
+}
+
+void
+isc_bitstring_copy(isc_bitstring_t *source, unsigned int sbitpos,
+                  isc_bitstring_t *target, unsigned int tbitpos,
+                  unsigned int n)
+{
+       unsigned int tlast;
+
+       /*
+        * Starting at bit 'sbitpos', copy 'n' bits from 'source' to
+        * the 'n' bits of 'target' starting at 'tbitpos'.
+        */
+
+       REQUIRE(VALID_BITSTRING(source));
+       REQUIRE(VALID_BITSTRING(target));
+       REQUIRE(source->lsb0 == target->lsb0);
+       if (source->lsb0) {
+               REQUIRE(sbitpos <= source->length);
+               sbitpos = PADDED(source->size) - sbitpos;
+               REQUIRE(sbitpos >= n);
+               sbitpos -= n;
+       } else
+               REQUIRE(sbitpos + n <= source->length);
+       tlast = tbitpos + n;
+       if (target->lsb0) {
+               REQUIRE(tbitpos <= target->length);
+               tbitpos = PADDED(target->size) - tbitpos;
+               REQUIRE(tbitpos >= n);
+               tbitpos -= n;
+       } else
+               REQUIRE(tlast <= target->size);
+
+       if (tlast > target->length)
+               target->length = tlast;
+
+       /*
+        * This is far from optimal...
+        */
+
+       while (n > 0) {
+               if (BITSET(source, sbitpos))
+                       SETBIT(target, tbitpos);
+               else
+                       CLEARBIT(target, tbitpos);
+               sbitpos++;
+               tbitpos++;
+               n--;
+       }
+}
diff --git a/lib/isc/buffer.c b/lib/isc/buffer.c
new file mode 100644 (file)
index 0000000..1b59e65
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: buffer.c,v 1.49 2008/09/25 04:02:39 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+void
+isc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length) {
+       /*
+        * Make 'b' refer to the 'length'-byte region starting at 'base'.
+        * XXXDCL see the comment in buffer.h about base being const.
+        */
+
+       REQUIRE(b != NULL);
+
+       ISC__BUFFER_INIT(b, base, length);
+}
+
+void
+isc__buffer_initnull(isc_buffer_t *b) {
+       /*
+        * Initialize a new buffer which has no backing store.  This can
+        * later be grown as needed and swapped in place.
+        */
+
+       ISC__BUFFER_INIT(b, NULL, 0);
+}
+
+void
+isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) {
+       /*
+        * Re-initialize the buffer enough to reconfigure the base of the
+        * buffer.  We will swap in the new buffer, after copying any
+        * data we contain into the new buffer and adjusting all of our
+        * internal pointers.
+        *
+        * The buffer must not be smaller than the length of the original
+        * buffer.
+        */
+       REQUIRE(b->length <= length);
+       REQUIRE(base != NULL);
+
+       (void)memmove(base, b->base, b->length);
+       b->base = base;
+       b->length = length;
+}
+
+void
+isc__buffer_invalidate(isc_buffer_t *b) {
+       /*
+        * Make 'b' an invalid buffer.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(!ISC_LINK_LINKED(b, link));
+       REQUIRE(b->mctx == NULL);
+
+       ISC__BUFFER_INVALIDATE(b);
+}
+
+void
+isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
+       /*
+        * Make 'r' refer to the region of 'b'.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(r != NULL);
+
+       ISC__BUFFER_REGION(b, r);
+}
+
+void
+isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) {
+       /*
+        * Make 'r' refer to the used region of 'b'.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(r != NULL);
+
+       ISC__BUFFER_USEDREGION(b, r);
+}
+
+void
+isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
+       /*
+        * Make 'r' refer to the available region of 'b'.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(r != NULL);
+
+       ISC__BUFFER_AVAILABLEREGION(b, r);
+}
+
+void
+isc__buffer_add(isc_buffer_t *b, unsigned int n) {
+       /*
+        * Increase the 'used' region of 'b' by 'n' bytes.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used + n <= b->length);
+
+       ISC__BUFFER_ADD(b, n);
+}
+
+void
+isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
+       /*
+        * Decrease the 'used' region of 'b' by 'n' bytes.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used >= n);
+
+       ISC__BUFFER_SUBTRACT(b, n);
+}
+
+void
+isc__buffer_clear(isc_buffer_t *b) {
+       /*
+        * Make the used region empty.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+
+       ISC__BUFFER_CLEAR(b);
+}
+
+void
+isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
+       /*
+        * Make 'r' refer to the consumed region of 'b'.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(r != NULL);
+
+       ISC__BUFFER_CONSUMEDREGION(b, r);
+}
+
+void
+isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
+       /*
+        * Make 'r' refer to the remaining region of 'b'.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(r != NULL);
+
+       ISC__BUFFER_REMAININGREGION(b, r);
+}
+
+void
+isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
+       /*
+        * Make 'r' refer to the active region of 'b'.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(r != NULL);
+
+       ISC__BUFFER_ACTIVEREGION(b, r);
+}
+
+void
+isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
+       /*
+        * Sets the end of the active region 'n' bytes after current.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->current + n <= b->used);
+
+       ISC__BUFFER_SETACTIVE(b, n);
+}
+
+void
+isc__buffer_first(isc_buffer_t *b) {
+       /*
+        * Make the consumed region empty.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+
+       ISC__BUFFER_FIRST(b);
+}
+
+void
+isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
+       /*
+        * Increase the 'consumed' region of 'b' by 'n' bytes.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->current + n <= b->used);
+
+       ISC__BUFFER_FORWARD(b, n);
+}
+
+void
+isc__buffer_back(isc_buffer_t *b, unsigned int n) {
+       /*
+        * Decrease the 'consumed' region of 'b' by 'n' bytes.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(n <= b->current);
+
+       ISC__BUFFER_BACK(b, n);
+}
+
+void
+isc_buffer_compact(isc_buffer_t *b) {
+       unsigned int length;
+       void *src;
+
+       /*
+        * Compact the used region by moving the remaining region so it occurs
+        * at the start of the buffer.  The used region is shrunk by the size
+        * of the consumed region, and the consumed region is then made empty.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+
+       src = isc_buffer_current(b);
+       length = isc_buffer_remaininglength(b);
+       (void)memmove(b->base, src, (size_t)length);
+
+       if (b->active > b->current)
+               b->active -= b->current;
+       else
+               b->active = 0;
+       b->current = 0;
+       b->used = length;
+}
+
+isc_uint8_t
+isc_buffer_getuint8(isc_buffer_t *b) {
+       unsigned char *cp;
+       isc_uint8_t result;
+
+       /*
+        * Read an unsigned 8-bit integer from 'b' and return it.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used - b->current >= 1);
+
+       cp = isc_buffer_current(b);
+       b->current += 1;
+       result = ((isc_uint8_t)(cp[0]));
+
+       return (result);
+}
+
+void
+isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) {
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used + 1 <= b->length);
+
+       ISC__BUFFER_PUTUINT8(b, val);
+}
+
+isc_uint16_t
+isc_buffer_getuint16(isc_buffer_t *b) {
+       unsigned char *cp;
+       isc_uint16_t result;
+
+       /*
+        * Read an unsigned 16-bit integer in network byte order from 'b',
+        * convert it to host byte order, and return it.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used - b->current >= 2);
+
+       cp = isc_buffer_current(b);
+       b->current += 2;
+       result = ((unsigned int)(cp[0])) << 8;
+       result |= ((unsigned int)(cp[1]));
+
+       return (result);
+}
+
+void
+isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) {
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used + 2 <= b->length);
+
+       ISC__BUFFER_PUTUINT16(b, val);
+}
+
+void
+isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val) {
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used + 3 <= b->length);
+
+       ISC__BUFFER_PUTUINT24(b, val);
+}
+
+isc_uint32_t
+isc_buffer_getuint32(isc_buffer_t *b) {
+       unsigned char *cp;
+       isc_uint32_t result;
+
+       /*
+        * Read an unsigned 32-bit integer in network byte order from 'b',
+        * convert it to host byte order, and return it.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used - b->current >= 4);
+
+       cp = isc_buffer_current(b);
+       b->current += 4;
+       result = ((unsigned int)(cp[0])) << 24;
+       result |= ((unsigned int)(cp[1])) << 16;
+       result |= ((unsigned int)(cp[2])) << 8;
+       result |= ((unsigned int)(cp[3]));
+
+       return (result);
+}
+
+void
+isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) {
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used + 4 <= b->length);
+
+       ISC__BUFFER_PUTUINT32(b, val);
+}
+
+isc_uint64_t
+isc_buffer_getuint48(isc_buffer_t *b) {
+       unsigned char *cp;
+       isc_uint64_t result;
+
+       /*
+        * Read an unsigned 48-bit integer in network byte order from 'b',
+        * convert it to host byte order, and return it.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used - b->current >= 6);
+
+       cp = isc_buffer_current(b);
+       b->current += 6;
+       result = ((isc_int64_t)(cp[0])) << 40;
+       result |= ((isc_int64_t)(cp[1])) << 32;
+       result |= ((isc_int64_t)(cp[2])) << 24;
+       result |= ((isc_int64_t)(cp[3])) << 16;
+       result |= ((isc_int64_t)(cp[4])) << 8;
+       result |= ((isc_int64_t)(cp[5]));
+
+       return (result);
+}
+
+void
+isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
+       isc_uint16_t valhi;
+       isc_uint32_t vallo;
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used + 6 <= b->length);
+
+       valhi = (isc_uint16_t)(val >> 32);
+       vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
+       ISC__BUFFER_PUTUINT16(b, valhi);
+       ISC__BUFFER_PUTUINT32(b, vallo);
+}
+
+void
+isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
+                  unsigned int length)
+{
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used + length <= b->length);
+
+       ISC__BUFFER_PUTMEM(b, base, length);
+}
+
+void
+isc__buffer_putstr(isc_buffer_t *b, const char *source) {
+       unsigned int l;
+       unsigned char *cp;
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(source != NULL);
+
+       /*
+        * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
+        */
+       l = strlen(source);
+
+       REQUIRE(l <= isc_buffer_availablelength(b));
+
+       cp = isc_buffer_used(b);
+       memcpy(cp, source, l);
+       b->used += l;
+}
+
+isc_result_t
+isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
+       unsigned char *base;
+       unsigned int available;
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(r != NULL);
+
+       /*
+        * XXXDCL
+        */
+       base = isc_buffer_used(b);
+       available = isc_buffer_availablelength(b);
+       if (r->length > available)
+               return (ISC_R_NOSPACE);
+       memcpy(base, r->base, r->length);
+       b->used += r->length;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
+                   unsigned int length)
+{
+       isc_buffer_t *dbuf;
+
+       REQUIRE(dynbuffer != NULL);
+       REQUIRE(*dynbuffer == NULL);
+
+       dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t));
+       if (dbuf == NULL)
+               return (ISC_R_NOMEMORY);
+
+       isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t),
+                       length);
+       dbuf->mctx = mctx;
+
+       *dynbuffer = dbuf;
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_buffer_free(isc_buffer_t **dynbuffer) {
+       unsigned int real_length;
+       isc_buffer_t *dbuf;
+       isc_mem_t *mctx;
+
+       REQUIRE(dynbuffer != NULL);
+       REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
+       REQUIRE((*dynbuffer)->mctx != NULL);
+
+       dbuf = *dynbuffer;
+       *dynbuffer = NULL;      /* destroy external reference */
+
+       real_length = dbuf->length + sizeof(isc_buffer_t);
+       mctx = dbuf->mctx;
+       dbuf->mctx = NULL;
+       isc_buffer_invalidate(dbuf);
+
+       isc_mem_put(mctx, dbuf, real_length);
+}
diff --git a/lib/isc/bufferlist.c b/lib/isc/bufferlist.c
new file mode 100644 (file)
index 0000000..0e5c125
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: bufferlist.c,v 1.17 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/buffer.h>
+#include <isc/bufferlist.h>
+#include <isc/util.h>
+
+unsigned int
+isc_bufferlist_usedcount(isc_bufferlist_t *bl) {
+       isc_buffer_t *buffer;
+       unsigned int length;
+
+       REQUIRE(bl != NULL);
+
+       length = 0;
+       buffer = ISC_LIST_HEAD(*bl);
+       while (buffer != NULL) {
+               REQUIRE(ISC_BUFFER_VALID(buffer));
+               length += isc_buffer_usedlength(buffer);
+               buffer = ISC_LIST_NEXT(buffer, link);
+       }
+
+       return (length);
+}
+
+unsigned int
+isc_bufferlist_availablecount(isc_bufferlist_t *bl) {
+       isc_buffer_t *buffer;
+       unsigned int length;
+
+       REQUIRE(bl != NULL);
+
+       length = 0;
+       buffer = ISC_LIST_HEAD(*bl);
+       while (buffer != NULL) {
+               REQUIRE(ISC_BUFFER_VALID(buffer));
+               length += isc_buffer_availablelength(buffer);
+               buffer = ISC_LIST_NEXT(buffer, link);
+       }
+
+       return (length);
+}
diff --git a/lib/isc/commandline.c b/lib/isc/commandline.c
new file mode 100644 (file)
index 0000000..aca1203
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Portions Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: commandline.c,v 1.22 2008/09/25 04:02:39 tbox Exp $ */
+
+/*! \file
+ * This file was adapted from the NetBSD project's source tree, RCS ID:
+ *    NetBSD: getopt.c,v 1.15 1999/09/20 04:39:37 lukem Exp
+ *
+ * The primary change has been to rename items to the ISC namespace
+ * and format in the ISC coding style.
+ */
+
+/*
+ * \author Principal Authors: Computer Systems Research Group at UC Berkeley
+ * \author Principal ISC caretaker: DCL
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <isc/commandline.h>
+#include <isc/msgs.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/*% Index into parent argv vector. */
+LIBISC_EXTERNAL_DATA int isc_commandline_index = 1;
+/*% Character checked for validity. */
+LIBISC_EXTERNAL_DATA int isc_commandline_option;
+/*% Argument associated with option. */
+LIBISC_EXTERNAL_DATA char *isc_commandline_argument;
+/*% For printing error messages. */
+LIBISC_EXTERNAL_DATA char *isc_commandline_progname;
+/*% Print error messages. */
+LIBISC_EXTERNAL_DATA isc_boolean_t isc_commandline_errprint = ISC_TRUE;
+/*% Reset processing. */
+LIBISC_EXTERNAL_DATA isc_boolean_t isc_commandline_reset = ISC_TRUE;
+
+static char endopt = '\0';
+
+#define        BADOPT  '?'
+#define        BADARG  ':'
+#define ENDOPT  &endopt
+
+/*!
+ * getopt --
+ *     Parse argc/argv argument vector.
+ */
+int
+isc_commandline_parse(int argc, char * const *argv, const char *options) {
+       static char *place = ENDOPT;
+       char *option;                   /* Index into *options of option. */
+
+       REQUIRE(argc >= 0 && argv != NULL && options != NULL);
+
+       /*
+        * Update scanning pointer, either because a reset was requested or
+        * the previous argv was finished.
+        */
+       if (isc_commandline_reset || *place == '\0') {
+               if (isc_commandline_reset) {
+                       isc_commandline_index = 1;
+                       isc_commandline_reset = ISC_FALSE;
+               }
+
+               if (isc_commandline_progname == NULL)
+                       isc_commandline_progname = argv[0];
+
+               if (isc_commandline_index >= argc ||
+                   *(place = argv[isc_commandline_index]) != '-') {
+                       /*
+                        * Index out of range or points to non-option.
+                        */
+                       place = ENDOPT;
+                       return (-1);
+               }
+
+               if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+                       /*
+                        * Found '--' to signal end of options.  Advance
+                        * index to next argv, the first non-option.
+                        */
+                       isc_commandline_index++;
+                       place = ENDOPT;
+                       return (-1);
+               }
+       }
+
+       isc_commandline_option = *place++;
+       option = strchr(options, isc_commandline_option);
+
+       /*
+        * Ensure valid option has been passed as specified by options string.
+        * '-:' is never a valid command line option because it could not
+        * distinguish ':' from the argument specifier in the options string.
+        */
+       if (isc_commandline_option == ':' || option == NULL) {
+               if (*place == '\0')
+                       isc_commandline_index++;
+
+               if (isc_commandline_errprint && *options != ':')
+                       fprintf(stderr, "%s: %s -- %c\n",
+                               isc_commandline_progname,
+                               isc_msgcat_get(isc_msgcat,
+                                              ISC_MSGSET_COMMANDLINE,
+                                              ISC_MSG_ILLEGALOPT,
+                                              "illegal option"),
+                               isc_commandline_option);
+
+               return (BADOPT);
+       }
+
+       if (*++option != ':') {
+               /*
+                * Option does not take an argument.
+                */
+               isc_commandline_argument = NULL;
+
+               /*
+                * Skip to next argv if at the end of the current argv.
+                */
+               if (*place == '\0')
+                       ++isc_commandline_index;
+
+       } else {
+               /*
+                * Option needs an argument.
+                */
+               if (*place != '\0')
+                       /*
+                        * Option is in this argv, -D1 style.
+                        */
+                       isc_commandline_argument = place;
+
+               else if (argc > ++isc_commandline_index)
+                       /*
+                        * Option is next argv, -D 1 style.
+                        */
+                       isc_commandline_argument = argv[isc_commandline_index];
+
+               else {
+                       /*
+                        * Argument needed, but no more argv.
+                        */
+                       place = ENDOPT;
+
+                       /*
+                        * Silent failure with "missing argument" return
+                        * when ':' starts options string, per historical spec.
+                        */
+                       if (*options == ':')
+                               return (BADARG);
+
+                       if (isc_commandline_errprint)
+                               fprintf(stderr, "%s: %s -- %c\n",
+                                       isc_commandline_progname,
+                                       isc_msgcat_get(isc_msgcat,
+                                                      ISC_MSGSET_COMMANDLINE,
+                                                      ISC_MSG_OPTNEEDARG,
+                                                      "option requires "
+                                                      "an argument"),
+                                       isc_commandline_option);
+
+                       return (BADOPT);
+               }
+
+               place = ENDOPT;
+
+               /*
+                * Point to argv that follows argument.
+                */
+               isc_commandline_index++;
+       }
+
+       return (isc_commandline_option);
+}
diff --git a/lib/isc/entropy.c b/lib/isc/entropy.c
new file mode 100644 (file)
index 0000000..25ab002
--- /dev/null
@@ -0,0 +1,1274 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: entropy.c,v 1.18.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+/*! \file
+ * \brief
+ * This is the system independent part of the entropy module.  It is
+ * compiled via inclusion from the relevant OS source file, ie,
+ * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
+ *
+ * \author Much of this code is modeled after the NetBSD /dev/random implementation,
+ * written by Michael Graff <explorer@netbsd.org>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <isc/buffer.h>
+#include <isc/entropy.h>
+#include <isc/keyboard.h>
+#include <isc/list.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/platform.h>
+#include <isc/region.h>
+#include <isc/sha1.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+
+#define ENTROPY_MAGIC          ISC_MAGIC('E', 'n', 't', 'e')
+#define SOURCE_MAGIC           ISC_MAGIC('E', 'n', 't', 's')
+
+#define VALID_ENTROPY(e)       ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
+#define VALID_SOURCE(s)                ISC_MAGIC_VALID(s, SOURCE_MAGIC)
+
+/***
+ *** "constants."  Do not change these unless you _really_ know what
+ *** you are doing.
+ ***/
+
+/*%
+ * Size of entropy pool in 32-bit words.  This _MUST_ be a power of 2.
+ */
+#define RND_POOLWORDS  128
+/*% Pool in bytes. */
+#define RND_POOLBYTES  (RND_POOLWORDS * 4)
+/*% Pool in bits. */
+#define RND_POOLBITS   (RND_POOLWORDS * 32)
+
+/*%
+ * Number of bytes returned per hash.  This must be true:
+ *     threshold * 2 <= digest_size_in_bytes
+ */
+#define RND_ENTROPY_THRESHOLD  10
+#define THRESHOLD_BITS         (RND_ENTROPY_THRESHOLD * 8)
+
+/*%
+ * Size of the input event queue in samples.
+ */
+#define RND_EVENTQSIZE 32
+
+/*%
+ * The number of times we'll "reseed" for pseudorandom seeds.  This is an
+ * extremely weak pseudorandom seed.  If the caller is using lots of
+ * pseudorandom data and they cannot provide a stronger random source,
+ * there is little we can do other than hope they're smart enough to
+ * call _adddata() with something better than we can come up with.
+ */
+#define RND_INITIALIZE 128
+
+/*% Entropy Pool */
+typedef struct {
+       isc_uint32_t    cursor;         /*%< current add point in the pool */
+       isc_uint32_t    entropy;        /*%< current entropy estimate in bits */
+       isc_uint32_t    pseudo;         /*%< bits extracted in pseudorandom */
+       isc_uint32_t    rotate;         /*%< how many bits to rotate by */
+       isc_uint32_t    pool[RND_POOLWORDS];    /*%< random pool data */
+} isc_entropypool_t;
+
+struct isc_entropy {
+       unsigned int                    magic;
+       isc_mem_t                      *mctx;
+       isc_mutex_t                     lock;
+       unsigned int                    refcnt;
+       isc_uint32_t                    initialized;
+       isc_uint32_t                    initcount;
+       isc_entropypool_t               pool;
+       unsigned int                    nsources;
+       isc_entropysource_t            *nextsource;
+       ISC_LIST(isc_entropysource_t)   sources;
+};
+
+/*% Sample Queue */
+typedef struct {
+       isc_uint32_t    last_time;      /*%< last time recorded */
+       isc_uint32_t    last_delta;     /*%< last delta value */
+       isc_uint32_t    last_delta2;    /*%< last delta2 value */
+       isc_uint32_t    nsamples;       /*%< number of samples filled in */
+       isc_uint32_t   *samples;        /*%< the samples */
+       isc_uint32_t   *extra;          /*%< extra samples added in */
+} sample_queue_t;
+
+typedef struct {
+       sample_queue_t  samplequeue;
+} isc_entropysamplesource_t;
+
+typedef struct {
+       isc_boolean_t           start_called;
+       isc_entropystart_t      startfunc;
+       isc_entropyget_t        getfunc;
+       isc_entropystop_t       stopfunc;
+       void                   *arg;
+       sample_queue_t          samplequeue;
+} isc_cbsource_t;
+
+typedef struct {
+       FILESOURCE_HANDLE_TYPE handle;
+} isc_entropyfilesource_t;
+
+struct isc_entropysource {
+       unsigned int    magic;
+       unsigned int    type;
+       isc_entropy_t  *ent;
+       isc_uint32_t    total;          /*%< entropy from this source */
+       ISC_LINK(isc_entropysource_t)   link;
+       char            name[32];
+       isc_boolean_t   bad;
+       isc_boolean_t   warn_keyboard;
+       isc_keyboard_t  kbd;
+       union {
+               isc_entropysamplesource_t       sample;
+               isc_entropyfilesource_t         file;
+               isc_cbsource_t                  callback;
+               isc_entropyusocketsource_t      usocket;
+       } sources;
+};
+
+#define ENTROPY_SOURCETYPE_SAMPLE      1       /*%< Type is a sample source */
+#define ENTROPY_SOURCETYPE_FILE                2       /*%< Type is a file source */
+#define ENTROPY_SOURCETYPE_CALLBACK    3       /*%< Type is a callback source */
+#define ENTROPY_SOURCETYPE_USOCKET     4       /*%< Type is a Unix socket source */
+
+/*@{*/
+/*%
+ * The random pool "taps"
+ */
+#define TAP1   99
+#define TAP2   59
+#define TAP3   31
+#define TAP4    9
+#define TAP5    7
+/*@}*/
+
+/*@{*/
+/*%
+ * Declarations for function provided by the system dependent sources that
+ * include this file.
+ */
+static void
+fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
+
+static int
+wait_for_sources(isc_entropy_t *);
+
+static void
+destroyfilesource(isc_entropyfilesource_t *source);
+
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source);
+
+/*@}*/
+
+static void
+samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
+       REQUIRE(sq->samples != NULL);
+       REQUIRE(sq->extra != NULL);
+
+       isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
+       isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
+       sq->samples = NULL;
+       sq->extra = NULL;
+}
+
+static isc_result_t
+samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
+       sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
+       if (sq->samples == NULL)
+               return (ISC_R_NOMEMORY);
+
+       sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
+       if (sq->extra == NULL) {
+               isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
+               sq->samples = NULL;
+               return (ISC_R_NOMEMORY);
+       }
+
+       sq->nsamples = 0;
+
+       return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Add in entropy, even when the value we're adding in could be
+ * very large.
+ */
+static inline void
+add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
+       /* clamp input.  Yes, this must be done. */
+       entropy = ISC_MIN(entropy, RND_POOLBITS);
+       /* Add in the entropy we already have. */
+       entropy += ent->pool.entropy;
+       /* Clamp. */
+       ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
+}
+
+/*%
+ * Decrement the amount of entropy the pool has.
+ */
+static inline void
+subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
+       entropy = ISC_MIN(entropy, ent->pool.entropy);
+       ent->pool.entropy -= entropy;
+}
+
+/*!
+ * Add in entropy, even when the value we're adding in could be
+ * very large.
+ */
+static inline void
+add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
+       /* clamp input.  Yes, this must be done. */
+       pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
+       /* Add in the pseudo we already have. */
+       pseudo += ent->pool.pseudo;
+       /* Clamp. */
+       ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
+}
+
+/*!
+ * Decrement the amount of pseudo the pool has.
+ */
+static inline void
+subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
+       pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
+       ent->pool.pseudo -= pseudo;
+}
+
+/*!
+ * Add one word to the pool, rotating the input as needed.
+ */
+static inline void
+entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
+       /*
+        * Steal some values out of the pool, and xor them into the
+        * word we were given.
+        *
+        * Mix the new value into the pool using xor.  This will
+        * prevent the actual values from being known to the caller
+        * since the previous values are assumed to be unknown as well.
+        */
+       val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
+       val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
+       val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
+       val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
+       val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
+       rp->pool[rp->cursor++] ^=
+         ((val << rp->rotate) | (val >> (32 - rp->rotate)));
+
+       /*
+        * If we have looped around the pool, increment the rotate
+        * variable so the next value will get xored in rotated to
+        * a different position.
+        * Increment by a value that is relatively prime to the word size
+        * to try to spread the bits throughout the pool quickly when the
+        * pool is empty.
+        */
+       if (rp->cursor == RND_POOLWORDS) {
+               rp->cursor = 0;
+               rp->rotate = (rp->rotate + 7) & 31;
+       }
+}
+
+/*!
+ * Add a buffer's worth of data to the pool.
+ *
+ * Requires that the lock is held on the entropy pool.
+ */
+static void
+entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
+                   isc_uint32_t entropy)
+{
+       isc_uint32_t val;
+       unsigned long addr;
+       isc_uint8_t *buf;
+
+       addr = (unsigned long)p;
+       buf = p;
+
+       if ((addr & 0x03U) != 0U) {
+               val = 0;
+               switch (len) {
+               case 3:
+                       val = *buf++;
+                       len--;
+               case 2:
+                       val = val << 8 | *buf++;
+                       len--;
+               case 1:
+                       val = val << 8 | *buf++;
+                       len--;
+               }
+
+               entropypool_add_word(&ent->pool, val);
+       }
+
+       for (; len > 3; len -= 4) {
+               val = *((isc_uint32_t *)buf);
+
+               entropypool_add_word(&ent->pool, val);
+               buf += 4;
+       }
+
+       if (len != 0) {
+               val = 0;
+               switch (len) {
+               case 3:
+                       val = *buf++;
+               case 2:
+                       val = val << 8 | *buf++;
+               case 1:
+                       val = val << 8 | *buf++;
+               }
+
+               entropypool_add_word(&ent->pool, val);
+       }
+
+       add_entropy(ent, entropy);
+       subtract_pseudo(ent, entropy);
+}
+
+static inline void
+reseed(isc_entropy_t *ent) {
+       isc_time_t t;
+       pid_t pid;
+
+       if (ent->initcount == 0) {
+               pid = getpid();
+               entropypool_adddata(ent, &pid, sizeof(pid), 0);
+               pid = getppid();
+               entropypool_adddata(ent, &pid, sizeof(pid), 0);
+       }
+
+       /*!
+        * After we've reseeded 100 times, only add new timing info every
+        * 50 requests.  This will keep us from using lots and lots of
+        * CPU just to return bad pseudorandom data anyway.
+        */
+       if (ent->initcount > 100)
+               if ((ent->initcount % 50) != 0)
+                       return;
+
+       TIME_NOW(&t);
+       entropypool_adddata(ent, &t, sizeof(t), 0);
+       ent->initcount++;
+}
+
+static inline unsigned int
+estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
+       isc_int32_t             delta;
+       isc_int32_t             delta2;
+       isc_int32_t             delta3;
+
+       /*!
+        * If the time counter has overflowed, calculate the real difference.
+        * If it has not, it is simpler.
+        */
+       if (t < sq->last_time)
+               delta = UINT_MAX - sq->last_time + t;
+       else
+               delta = sq->last_time - t;
+
+       if (delta < 0)
+               delta = -delta;
+
+       /*
+        * Calculate the second and third order differentials
+        */
+       delta2 = sq->last_delta - delta;
+       if (delta2 < 0)
+               delta2 = -delta2;
+
+       delta3 = sq->last_delta2 - delta2;
+       if (delta3 < 0)
+               delta3 = -delta3;
+
+       sq->last_time = t;
+       sq->last_delta = delta;
+       sq->last_delta2 = delta2;
+
+       /*
+        * If any delta is 0, we got no entropy.  If all are non-zero, we
+        * might have something.
+        */
+       if (delta == 0 || delta2 == 0 || delta3 == 0)
+               return 0;
+
+       /*
+        * We could find the smallest delta and claim we got log2(delta)
+        * bits, but for now return that we found 1 bit.
+        */
+       return 1;
+}
+
+static unsigned int
+crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
+       unsigned int ns;
+       unsigned int added;
+
+       if (sq->nsamples < 6)
+               return (0);
+
+       added = 0;
+       sq->last_time = sq->samples[0];
+       sq->last_delta = 0;
+       sq->last_delta2 = 0;
+
+       /*
+        * Prime the values by adding in the first 4 samples in.  This
+        * should completely initialize the delta calculations.
+        */
+       for (ns = 0; ns < 4; ns++)
+               (void)estimate_entropy(sq, sq->samples[ns]);
+
+       for (ns = 4; ns < sq->nsamples; ns++)
+               added += estimate_entropy(sq, sq->samples[ns]);
+
+       entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
+       entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
+
+       /*
+        * Move the last 4 samples into the first 4 positions, and start
+        * adding new samples from that point.
+        */
+       for (ns = 0; ns < 4; ns++) {
+               sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
+               sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
+       }
+
+       sq->nsamples = 4;
+
+       return (added);
+}
+
+static unsigned int
+get_from_callback(isc_entropysource_t *source, unsigned int desired,
+                 isc_boolean_t blocking)
+{
+       isc_entropy_t *ent = source->ent;
+       isc_cbsource_t *cbs = &source->sources.callback;
+       unsigned int added;
+       unsigned int got;
+       isc_result_t result;
+
+       if (desired == 0)
+               return (0);
+
+       if (source->bad)
+               return (0);
+
+       if (!cbs->start_called && cbs->startfunc != NULL) {
+               result = cbs->startfunc(source, cbs->arg, blocking);
+               if (result != ISC_R_SUCCESS)
+                       return (0);
+               cbs->start_called = ISC_TRUE;
+       }
+
+       added = 0;
+       result = ISC_R_SUCCESS;
+       while (desired > 0 && result == ISC_R_SUCCESS) {
+               result = cbs->getfunc(source, cbs->arg, blocking);
+               if (result == ISC_R_QUEUEFULL) {
+                       got = crunchsamples(ent, &cbs->samplequeue);
+                       added += got;
+                       desired -= ISC_MIN(got, desired);
+                       result = ISC_R_SUCCESS;
+               } else if (result != ISC_R_SUCCESS &&
+                          result != ISC_R_NOTBLOCKING)
+                       source->bad = ISC_TRUE;
+
+       }
+
+       return (added);
+}
+
+/*
+ * Extract some number of bytes from the random pool, decreasing the
+ * estimate of randomness as each byte is extracted.
+ *
+ * Do this by stiring the pool and returning a part of hash as randomness.
+ * Note that no secrets are given away here since parts of the hash are
+ * xored together before returned.
+ *
+ * Honor the request from the caller to only return good data, any data,
+ * etc.
+ */
+isc_result_t
+isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
+                   unsigned int *returned, unsigned int flags)
+{
+       unsigned int i;
+       isc_sha1_t hash;
+       unsigned char digest[ISC_SHA1_DIGESTLENGTH];
+       isc_uint32_t remain, deltae, count, total;
+       isc_uint8_t *buf;
+       isc_boolean_t goodonly, partial, blocking;
+
+       REQUIRE(VALID_ENTROPY(ent));
+       REQUIRE(data != NULL);
+       REQUIRE(length > 0);
+
+       goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
+       partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
+       blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
+
+       REQUIRE(!partial || returned != NULL);
+
+       LOCK(&ent->lock);
+
+       remain = length;
+       buf = data;
+       total = 0;
+       while (remain != 0) {
+               count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
+
+               /*
+                * If we are extracting good data only, make certain we
+                * have enough data in our pool for this pass.  If we don't,
+                * get some, and fail if we can't, and partial returns
+                * are not ok.
+                */
+               if (goodonly) {
+                       unsigned int fillcount;
+
+                       fillcount = ISC_MAX(remain * 8, count * 8);
+
+                       /*
+                        * If, however, we have at least THRESHOLD_BITS
+                        * of entropy in the pool, don't block here.  It is
+                        * better to drain the pool once in a while and
+                        * then refill it than it is to constantly keep the
+                        * pool full.
+                        */
+                       if (ent->pool.entropy >= THRESHOLD_BITS)
+                               fillpool(ent, fillcount, ISC_FALSE);
+                       else
+                               fillpool(ent, fillcount, blocking);
+
+                       /*
+                        * Verify that we got enough entropy to do one
+                        * extraction.  If we didn't, bail.
+                        */
+                       if (ent->pool.entropy < THRESHOLD_BITS) {
+                               if (!partial)
+                                       goto zeroize;
+                               else
+                                       goto partial_output;
+                       }
+               } else {
+                       /*
+                        * If we've extracted half our pool size in bits
+                        * since the last refresh, try to refresh here.
+                        */
+                       if (ent->initialized < THRESHOLD_BITS)
+                               fillpool(ent, THRESHOLD_BITS, blocking);
+                       else
+                               fillpool(ent, 0, ISC_FALSE);
+
+                       /*
+                        * If we've not initialized with enough good random
+                        * data, seed with our crappy code.
+                        */
+                       if (ent->initialized < THRESHOLD_BITS)
+                               reseed(ent);
+               }
+
+               isc_sha1_init(&hash);
+               isc_sha1_update(&hash, (void *)(ent->pool.pool),
+                               RND_POOLBYTES);
+               isc_sha1_final(&hash, digest);
+
+               /*
+                * Stir the extracted data (all of it) back into the pool.
+                */
+               entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
+
+               for (i = 0; i < count; i++)
+                       buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
+
+               buf += count;
+               remain -= count;
+
+               deltae = count * 8;
+               deltae = ISC_MIN(deltae, ent->pool.entropy);
+               total += deltae;
+               subtract_entropy(ent, deltae);
+               add_pseudo(ent, count * 8);
+       }
+
+ partial_output:
+       memset(digest, 0, sizeof(digest));
+
+       if (returned != NULL)
+               *returned = (length - remain);
+
+       UNLOCK(&ent->lock);
+
+       return (ISC_R_SUCCESS);
+
+ zeroize:
+       /* put the entropy we almost extracted back */
+       add_entropy(ent, total);
+       memset(data, 0, length);
+       memset(digest, 0, sizeof(digest));
+       if (returned != NULL)
+               *returned = 0;
+
+       UNLOCK(&ent->lock);
+
+       return (ISC_R_NOENTROPY);
+}
+
+static void
+isc_entropypool_init(isc_entropypool_t *pool) {
+       pool->cursor = RND_POOLWORDS - 1;
+       pool->entropy = 0;
+       pool->pseudo = 0;
+       pool->rotate = 0;
+       memset(pool->pool, 0, RND_POOLBYTES);
+}
+
+static void
+isc_entropypool_invalidate(isc_entropypool_t *pool) {
+       pool->cursor = 0;
+       pool->entropy = 0;
+       pool->pseudo = 0;
+       pool->rotate = 0;
+       memset(pool->pool, 0, RND_POOLBYTES);
+}
+
+isc_result_t
+isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
+       isc_result_t result;
+       isc_entropy_t *ent;
+
+       REQUIRE(mctx != NULL);
+       REQUIRE(entp != NULL && *entp == NULL);
+
+       ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
+       if (ent == NULL)
+               return (ISC_R_NOMEMORY);
+
+       /*
+        * We need a lock.
+        */
+       result = isc_mutex_init(&ent->lock);
+       if (result != ISC_R_SUCCESS)
+               goto errout;
+
+       /*
+        * From here down, no failures will/can occur.
+        */
+       ISC_LIST_INIT(ent->sources);
+       ent->nextsource = NULL;
+       ent->nsources = 0;
+       ent->mctx = NULL;
+       isc_mem_attach(mctx, &ent->mctx);
+       ent->refcnt = 1;
+       ent->initialized = 0;
+       ent->initcount = 0;
+       ent->magic = ENTROPY_MAGIC;
+
+       isc_entropypool_init(&ent->pool);
+
+       *entp = ent;
+       return (ISC_R_SUCCESS);
+
+ errout:
+       isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
+
+       return (result);
+}
+
+/*!
+ * Requires "ent" be locked.
+ */
+static void
+destroysource(isc_entropysource_t **sourcep) {
+       isc_entropysource_t *source;
+       isc_entropy_t *ent;
+       isc_cbsource_t *cbs;
+
+       source = *sourcep;
+       *sourcep = NULL;
+       ent = source->ent;
+
+       ISC_LIST_UNLINK(ent->sources, source, link);
+       ent->nextsource = NULL;
+       REQUIRE(ent->nsources > 0);
+       ent->nsources--;
+
+       switch (source->type) {
+       case ENTROPY_SOURCETYPE_FILE:
+               if (! source->bad)
+                       destroyfilesource(&source->sources.file);
+               break;
+       case ENTROPY_SOURCETYPE_USOCKET:
+               if (! source->bad)
+                       destroyusocketsource(&source->sources.usocket);
+               break;
+       case ENTROPY_SOURCETYPE_SAMPLE:
+               samplequeue_release(ent, &source->sources.sample.samplequeue);
+               break;
+       case ENTROPY_SOURCETYPE_CALLBACK:
+               cbs = &source->sources.callback;
+               if (cbs->start_called && cbs->stopfunc != NULL) {
+                       cbs->stopfunc(source, cbs->arg);
+                       cbs->start_called = ISC_FALSE;
+               }
+               samplequeue_release(ent, &cbs->samplequeue);
+               break;
+       }
+
+       memset(source, 0, sizeof(isc_entropysource_t));
+
+       isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+}
+
+static inline isc_boolean_t
+destroy_check(isc_entropy_t *ent) {
+       isc_entropysource_t *source;
+
+       if (ent->refcnt > 0)
+               return (ISC_FALSE);
+
+       source = ISC_LIST_HEAD(ent->sources);
+       while (source != NULL) {
+               switch (source->type) {
+               case ENTROPY_SOURCETYPE_FILE:
+               case ENTROPY_SOURCETYPE_USOCKET:
+                       break;
+               default:
+                       return (ISC_FALSE);
+               }
+               source = ISC_LIST_NEXT(source, link);
+       }
+
+       return (ISC_TRUE);
+}
+
+static void
+destroy(isc_entropy_t **entp) {
+       isc_entropy_t *ent;
+       isc_entropysource_t *source;
+       isc_mem_t *mctx;
+
+       REQUIRE(entp != NULL && *entp != NULL);
+       ent = *entp;
+       *entp = NULL;
+
+       LOCK(&ent->lock);
+
+       REQUIRE(ent->refcnt == 0);
+
+       /*
+        * Here, detach non-sample sources.
+        */
+       source = ISC_LIST_HEAD(ent->sources);
+       while (source != NULL) {
+               switch(source->type) {
+               case ENTROPY_SOURCETYPE_FILE:
+               case ENTROPY_SOURCETYPE_USOCKET:
+                       destroysource(&source);
+                       break;
+               }
+               source = ISC_LIST_HEAD(ent->sources);
+       }
+
+       /*
+        * If there are other types of sources, we've found a bug.
+        */
+       REQUIRE(ISC_LIST_EMPTY(ent->sources));
+
+       mctx = ent->mctx;
+
+       isc_entropypool_invalidate(&ent->pool);
+
+       UNLOCK(&ent->lock);
+
+       DESTROYLOCK(&ent->lock);
+
+       memset(ent, 0, sizeof(isc_entropy_t));
+       isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
+       isc_mem_detach(&mctx);
+}
+
+void
+isc_entropy_destroysource(isc_entropysource_t **sourcep) {
+       isc_entropysource_t *source;
+       isc_entropy_t *ent;
+       isc_boolean_t killit;
+
+       REQUIRE(sourcep != NULL);
+       REQUIRE(VALID_SOURCE(*sourcep));
+
+       source = *sourcep;
+       *sourcep = NULL;
+
+       ent = source->ent;
+       REQUIRE(VALID_ENTROPY(ent));
+
+       LOCK(&ent->lock);
+
+       destroysource(&source);
+
+       killit = destroy_check(ent);
+
+       UNLOCK(&ent->lock);
+
+       if (killit)
+               destroy(&ent);
+}
+
+isc_result_t
+isc_entropy_createcallbacksource(isc_entropy_t *ent,
+                                isc_entropystart_t start,
+                                isc_entropyget_t get,
+                                isc_entropystop_t stop,
+                                void *arg,
+                                isc_entropysource_t **sourcep)
+{
+       isc_result_t result;
+       isc_entropysource_t *source;
+       isc_cbsource_t *cbs;
+
+       REQUIRE(VALID_ENTROPY(ent));
+       REQUIRE(get != NULL);
+       REQUIRE(sourcep != NULL && *sourcep == NULL);
+
+       LOCK(&ent->lock);
+
+       source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+       if (source == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto errout;
+       }
+       source->bad = ISC_FALSE;
+
+       cbs = &source->sources.callback;
+
+       result = samplesource_allocate(ent, &cbs->samplequeue);
+       if (result != ISC_R_SUCCESS)
+               goto errout;
+
+       cbs->start_called = ISC_FALSE;
+       cbs->startfunc = start;
+       cbs->getfunc = get;
+       cbs->stopfunc = stop;
+       cbs->arg = arg;
+
+       /*
+        * From here down, no failures can occur.
+        */
+       source->magic = SOURCE_MAGIC;
+       source->type = ENTROPY_SOURCETYPE_CALLBACK;
+       source->ent = ent;
+       source->total = 0;
+       memset(source->name, 0, sizeof(source->name));
+       ISC_LINK_INIT(source, link);
+
+       /*
+        * Hook it into the entropy system.
+        */
+       ISC_LIST_APPEND(ent->sources, source, link);
+       ent->nsources++;
+
+       *sourcep = source;
+
+       UNLOCK(&ent->lock);
+       return (ISC_R_SUCCESS);
+
+ errout:
+       if (source != NULL)
+               isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+
+       UNLOCK(&ent->lock);
+
+       return (result);
+}
+
+void
+isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
+       isc_entropysource_t *source;
+       isc_cbsource_t *cbs;
+
+       REQUIRE(VALID_ENTROPY(ent));
+
+       LOCK(&ent->lock);
+
+       source = ISC_LIST_HEAD(ent->sources);
+       while (source != NULL) {
+               if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
+                       cbs = &source->sources.callback;
+                       if (cbs->start_called && cbs->stopfunc != NULL) {
+                               cbs->stopfunc(source, cbs->arg);
+                               cbs->start_called = ISC_FALSE;
+                       }
+               }
+
+               source = ISC_LIST_NEXT(source, link);
+       }
+
+       UNLOCK(&ent->lock);
+}
+
+isc_result_t
+isc_entropy_createsamplesource(isc_entropy_t *ent,
+                              isc_entropysource_t **sourcep)
+{
+       isc_result_t result;
+       isc_entropysource_t *source;
+       sample_queue_t *sq;
+
+       REQUIRE(VALID_ENTROPY(ent));
+       REQUIRE(sourcep != NULL && *sourcep == NULL);
+
+       LOCK(&ent->lock);
+
+       source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+       if (source == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto errout;
+       }
+
+       sq = &source->sources.sample.samplequeue;
+       result = samplesource_allocate(ent, sq);
+       if (result != ISC_R_SUCCESS)
+               goto errout;
+
+       /*
+        * From here down, no failures can occur.
+        */
+       source->magic = SOURCE_MAGIC;
+       source->type = ENTROPY_SOURCETYPE_SAMPLE;
+       source->ent = ent;
+       source->total = 0;
+       memset(source->name, 0, sizeof(source->name));
+       ISC_LINK_INIT(source, link);
+
+       /*
+        * Hook it into the entropy system.
+        */
+       ISC_LIST_APPEND(ent->sources, source, link);
+       ent->nsources++;
+
+       *sourcep = source;
+
+       UNLOCK(&ent->lock);
+       return (ISC_R_SUCCESS);
+
+ errout:
+       if (source != NULL)
+               isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+
+       UNLOCK(&ent->lock);
+
+       return (result);
+}
+
+/*!
+ * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
+ * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
+ * queue was full when this function was called.
+ */
+static isc_result_t
+addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
+       if (sq->nsamples >= RND_EVENTQSIZE)
+               return (ISC_R_NOMORE);
+
+       sq->samples[sq->nsamples] = sample;
+       sq->extra[sq->nsamples] = extra;
+       sq->nsamples++;
+
+       if (sq->nsamples >= RND_EVENTQSIZE)
+               return (ISC_R_QUEUEFULL);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
+                     isc_uint32_t extra)
+{
+       isc_entropy_t *ent;
+       sample_queue_t *sq;
+       unsigned int entropy;
+       isc_result_t result;
+
+       REQUIRE(VALID_SOURCE(source));
+
+       ent = source->ent;
+
+       LOCK(&ent->lock);
+
+       sq = &source->sources.sample.samplequeue;
+       result = addsample(sq, sample, extra);
+       if (result == ISC_R_QUEUEFULL) {
+               entropy = crunchsamples(ent, sq);
+               add_entropy(ent, entropy);
+       }
+
+       UNLOCK(&ent->lock);
+
+       return (result);
+}
+
+isc_result_t
+isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
+                             isc_uint32_t extra)
+{
+       sample_queue_t *sq;
+       isc_result_t result;
+
+       REQUIRE(VALID_SOURCE(source));
+       REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
+
+       sq = &source->sources.callback.samplequeue;
+       result = addsample(sq, sample, extra);
+
+       return (result);
+}
+
+void
+isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
+                   isc_uint32_t entropy)
+{
+       REQUIRE(VALID_ENTROPY(ent));
+
+       LOCK(&ent->lock);
+
+       entropypool_adddata(ent, data, length, entropy);
+
+       if (ent->initialized < THRESHOLD_BITS)
+               ent->initialized = THRESHOLD_BITS;
+
+       UNLOCK(&ent->lock);
+}
+
+static void
+dumpstats(isc_entropy_t *ent, FILE *out) {
+       fprintf(out,
+               isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
+                              ISC_MSG_ENTROPYSTATS,
+                              "Entropy pool %p:  refcnt %u cursor %u,"
+                              " rotate %u entropy %u pseudo %u nsources %u"
+                              " nextsource %p initialized %u initcount %u\n"),
+               ent, ent->refcnt,
+               ent->pool.cursor, ent->pool.rotate,
+               ent->pool.entropy, ent->pool.pseudo,
+               ent->nsources, ent->nextsource, ent->initialized,
+               ent->initcount);
+}
+
+/*
+ * This function ignores locking.  Use at your own risk.
+ */
+void
+isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
+       REQUIRE(VALID_ENTROPY(ent));
+
+       LOCK(&ent->lock);
+       dumpstats(ent, out);
+       UNLOCK(&ent->lock);
+}
+
+unsigned int
+isc_entropy_status(isc_entropy_t *ent) {
+       unsigned int estimate;
+
+       LOCK(&ent->lock);
+       estimate = ent->pool.entropy;
+       UNLOCK(&ent->lock);
+
+       return estimate;
+}
+
+void
+isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
+       REQUIRE(VALID_ENTROPY(ent));
+       REQUIRE(entp != NULL && *entp == NULL);
+
+       LOCK(&ent->lock);
+
+       ent->refcnt++;
+       *entp = ent;
+
+       UNLOCK(&ent->lock);
+}
+
+void
+isc_entropy_detach(isc_entropy_t **entp) {
+       isc_entropy_t *ent;
+       isc_boolean_t killit;
+
+       REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
+       ent = *entp;
+       *entp = NULL;
+
+       LOCK(&ent->lock);
+
+       REQUIRE(ent->refcnt > 0);
+       ent->refcnt--;
+
+       killit = destroy_check(ent);
+
+       UNLOCK(&ent->lock);
+
+       if (killit)
+               destroy(&ent);
+}
+
+static isc_result_t
+kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
+       /*
+        * The intent of "first" is to provide a warning message only once
+        * during the run of a program that might try to gather keyboard
+        * entropy multiple times.
+        */
+       static isc_boolean_t first = ISC_TRUE;
+
+       UNUSED(arg);
+
+       if (! blocking)
+               return (ISC_R_NOENTROPY);
+
+       if (first) {
+               if (source->warn_keyboard)
+                       fprintf(stderr, "You must use the keyboard to create "
+                               "entropy, since your system is lacking\n"
+                               "/dev/random (or equivalent)\n\n");
+               first = ISC_FALSE;
+       }
+       fprintf(stderr, "start typing:\n");
+
+       return (isc_keyboard_open(&source->kbd));
+}
+
+static void
+kbdstop(isc_entropysource_t *source, void *arg) {
+
+       UNUSED(arg);
+
+       if (! isc_keyboard_canceled(&source->kbd))
+               fprintf(stderr, "stop typing.\r\n");
+
+       (void)isc_keyboard_close(&source->kbd, 3);
+}
+
+static isc_result_t
+kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
+       isc_result_t result;
+       isc_time_t t;
+       isc_uint32_t sample;
+       isc_uint32_t extra;
+       unsigned char c;
+
+       UNUSED(arg);
+
+       if (!blocking)
+               return (ISC_R_NOTBLOCKING);
+
+       result = isc_keyboard_getchar(&source->kbd, &c);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       TIME_NOW(&t);
+
+       sample = isc_time_nanoseconds(&t);
+       extra = c;
+
+       result = isc_entropy_addcallbacksample(source, sample, extra);
+       if (result != ISC_R_SUCCESS) {
+               fprintf(stderr, "\r\n");
+               return (result);
+       }
+
+       fprintf(stderr, ".");
+       fflush(stderr);
+
+       return (result);
+}
+
+isc_result_t
+isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
+                         const char *randomfile, int use_keyboard)
+{
+       isc_result_t result;
+       isc_result_t final_result = ISC_R_NOENTROPY;
+       isc_boolean_t userfile = ISC_TRUE;
+
+       REQUIRE(VALID_ENTROPY(ectx));
+       REQUIRE(source != NULL && *source == NULL);
+       REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
+               use_keyboard == ISC_ENTROPY_KEYBOARDNO  ||
+               use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
+
+#ifdef PATH_RANDOMDEV
+       if (randomfile == NULL) {
+               randomfile = PATH_RANDOMDEV;
+               userfile = ISC_FALSE;
+       }
+#endif
+
+       if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
+               result = isc_entropy_createfilesource(ectx, randomfile);
+               if (result == ISC_R_SUCCESS &&
+                   use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
+                       use_keyboard = ISC_ENTROPY_KEYBOARDNO;
+               if (result != ISC_R_SUCCESS && userfile)
+                       return (result);
+
+               final_result = result;
+       }
+
+       if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
+               result = isc_entropy_createcallbacksource(ectx, kbdstart,
+                                                         kbdget, kbdstop,
+                                                         NULL, source);
+               if (result == ISC_R_SUCCESS)
+                       (*source)->warn_keyboard =
+                               ISC_TF(use_keyboard ==
+                                      ISC_ENTROPY_KEYBOARDMAYBE);
+
+               if (final_result != ISC_R_SUCCESS)
+                       final_result = result;
+       }
+
+       /*
+        * final_result is ISC_R_SUCCESS if at least one source of entropy
+        * could be started, otherwise it is the error from the most recently
+        * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
+        * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
+        */
+       return (final_result);
+}
index ed0469d1017bca366e0db424ac6547e660229fa1..095100a7c9436651cc7144cd1e1eaa41cab3d6f5 100644 (file)
@@ -1,21 +1,23 @@
 /*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: error.c,v 1.16 2001/08/08 22:54:49 gson Exp $ */
+/* $Id: error.c,v 1.21 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
 
 #include <config.h>
 
 #include <isc/error.h>
 #include <isc/msgs.h>
 
+/*% Default unexpected callback. */
 static void
 default_unexpected_callback(const char *, int, const char *, va_list)
      ISC_FORMAT_PRINTF(3, 0);
 
+/*% Default fatal callback. */
 static void
 default_fatal_callback(const char *, int, const char *, va_list)
      ISC_FORMAT_PRINTF(3, 0);
 
+/*% unexpected_callback */
 static isc_errorcallback_t unexpected_callback = default_unexpected_callback;
 static isc_errorcallback_t fatal_callback = default_fatal_callback;
 
diff --git a/lib/isc/event.c b/lib/isc/event.c
new file mode 100644 (file)
index 0000000..8ab7524
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: event.c,v 1.21 2007/06/19 23:47:17 tbox Exp $ */
+
+/*!
+ * \file
+ * \author Principal Author: Bob Halley
+ */
+
+#include <config.h>
+
+#include <isc/event.h>
+#include <isc/mem.h>
+#include <isc/util.h>
+
+/***
+ *** Events.
+ ***/
+
+static void
+destroy(isc_event_t *event) {
+       isc_mem_t *mctx = event->ev_destroy_arg;
+
+       isc_mem_put(mctx, event, event->ev_size);
+}
+
+isc_event_t *
+isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+                  isc_taskaction_t action, const void *arg, size_t size)
+{
+       isc_event_t *event;
+       void *deconst_arg;
+
+       REQUIRE(size >= sizeof(struct isc_event));
+       REQUIRE(action != NULL);
+
+       event = isc_mem_get(mctx, size);
+       if (event == NULL)
+               return (NULL);
+
+       /*
+        * Removing the const attribute from "arg" is the best of two
+        * evils here.  If the event->ev_arg member is made const, then
+        * it affects a great many users of the task/event subsystem
+        * which are not passing in an "arg" which starts its life as
+        * const.  Changing isc_event_allocate() and isc_task_onshutdown()
+        * to not have "arg" prototyped as const (which is quite legitimate,
+        * because neither of those functions modify arg) can cause
+        * compiler whining anytime someone does want to use a const
+        * arg that they themselves never modify, such as with
+        * gcc -Wwrite-strings and using a string "arg".
+        */
+       DE_CONST(arg, deconst_arg);
+
+       ISC_EVENT_INIT(event, size, 0, NULL, type, action, deconst_arg,
+                      sender, destroy, mctx);
+
+       return (event);
+}
+
+void
+isc_event_free(isc_event_t **eventp) {
+       isc_event_t *event;
+
+       REQUIRE(eventp != NULL);
+       event = *eventp;
+       REQUIRE(event != NULL);
+
+       if (event->ev_destroy != NULL)
+               (event->ev_destroy)(event);
+
+       *eventp = NULL;
+}
diff --git a/lib/isc/fsaccess.c b/lib/isc/fsaccess.c
new file mode 100644 (file)
index 0000000..5c97183
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: fsaccess.c,v 1.10 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file
+ * \brief
+ * This file contains the OS-independent functionality of the API.
+ */
+#include <isc/fsaccess.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+/*!
+ * Shorthand.  Maybe ISC__FSACCESS_PERMISSIONBITS should not even be in
+ * <isc/fsaccess.h>.  Could check consistency with sizeof(isc_fsaccess_t)
+ * and the number of bits in each function.
+ */
+#define STEP           (ISC__FSACCESS_PERMISSIONBITS)
+#define GROUP          (STEP)
+#define OTHER          (STEP * 2)
+
+void
+isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access) {
+       REQUIRE(trustee <= 0x7);
+       REQUIRE(permission <= 0xFF);
+
+       if ((trustee & ISC_FSACCESS_OWNER) != 0)
+               *access |= permission;
+
+       if ((trustee & ISC_FSACCESS_GROUP) != 0)
+               *access |= (permission << GROUP);
+
+       if ((trustee & ISC_FSACCESS_OTHER) != 0)
+               *access |= (permission << OTHER);
+}
+
+void
+isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access) {
+       REQUIRE(trustee <= 0x7);
+       REQUIRE(permission <= 0xFF);
+
+
+       if ((trustee & ISC_FSACCESS_OWNER) != 0)
+               *access &= ~permission;
+
+       if ((trustee & ISC_FSACCESS_GROUP) != 0)
+               *access &= ~(permission << GROUP);
+
+       if ((trustee & ISC_FSACCESS_OTHER) != 0)
+               *access &= ~(permission << OTHER);
+}
+
+static isc_result_t
+check_bad_bits(isc_fsaccess_t access, isc_boolean_t is_dir) {
+       isc_fsaccess_t bits;
+
+       /*
+        * Check for disallowed user bits.
+        */
+       if (is_dir)
+               bits = ISC_FSACCESS_READ |
+                      ISC_FSACCESS_WRITE |
+                      ISC_FSACCESS_EXECUTE;
+       else
+               bits = ISC_FSACCESS_CREATECHILD |
+                      ISC_FSACCESS_ACCESSCHILD |
+                      ISC_FSACCESS_DELETECHILD |
+                      ISC_FSACCESS_LISTDIRECTORY;
+
+       /*
+        * Set group bad bits.
+        */
+       bits |= bits << STEP;
+       /*
+        * Set other bad bits.
+        */
+       bits |= bits << STEP;
+
+       if ((access & bits) != 0) {
+               if (is_dir)
+                       return (ISC_R_NOTFILE);
+               else
+                       return (ISC_R_NOTDIRECTORY);
+       }
+
+       return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/hash.c b/lib/isc/hash.c
new file mode 100644 (file)
index 0000000..9911bde
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hash.c,v 1.13.332.3 2009/05/07 23:47:12 tbox Exp $ */
+
+/*! \file
+ * Some portion of this code was derived from universal hash function
+ * libraries of Rice University.
+\section license UH Universal Hashing Library
+
+Copyright ((c)) 2002, Rice University
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+    copyright notice, this list of conditions and the following
+    disclaimer in the documentation and/or other materials provided
+    with the distribution.
+
+    * Neither the name of Rice University (RICE) nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+
+This software is provided by RICE and the contributors on an "as is"
+basis, without any representations or warranties of any kind, express
+or implied including, but not limited to, representations or
+warranties of non-infringement, merchantability or fitness for a
+particular purpose. In no event shall RICE or contributors be liable
+for any direct, indirect, incidental, special, exemplary, or
+consequential damages (including, but not limited to, procurement of
+substitute goods or services; loss of use, data, or profits; or
+business interruption) however caused and on any theory of liability,
+whether in contract, strict liability, or tort (including negligence
+or otherwise) arising in any way out of the use of this software, even
+if advised of the possibility of such damage.
+*/
+
+#include <config.h>
+
+#include <isc/entropy.h>
+#include <isc/hash.h>
+#include <isc/mem.h>
+#include <isc/magic.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/random.h>
+#include <isc/refcount.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define HASH_MAGIC             ISC_MAGIC('H', 'a', 's', 'h')
+#define VALID_HASH(h)          ISC_MAGIC_VALID((h), HASH_MAGIC)
+
+/*%
+ * A large 32-bit prime number that specifies the range of the hash output.
+ */
+#define PRIME32 0xFFFFFFFB              /* 2^32 -  5 */
+
+/*@{*/
+/*%
+ * Types of random seed and hash accumulator.  Perhaps they can be system
+ * dependent.
+ */
+typedef isc_uint32_t hash_accum_t;
+typedef isc_uint16_t hash_random_t;
+/*@}*/
+
+/*% isc hash structure */
+struct isc_hash {
+       unsigned int    magic;
+       isc_mem_t       *mctx;
+       isc_mutex_t     lock;
+       isc_boolean_t   initialized;
+       isc_refcount_t  refcnt;
+       isc_entropy_t   *entropy; /*%< entropy source */
+       unsigned int    limit;  /*%< upper limit of key length */
+       size_t          vectorlen; /*%< size of the vector below */
+       hash_random_t   *rndvector; /*%< random vector for universal hashing */
+};
+
+static isc_mutex_t createlock;
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_hash_t *hash = NULL;
+
+static unsigned char maptolower[] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+       0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+       0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+       0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+       0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+       0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+       0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+       0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+       0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+       0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+       0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+       0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+       0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+isc_result_t
+isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy,
+                  unsigned int limit, isc_hash_t **hctxp)
+{
+       isc_result_t result;
+       isc_hash_t *hctx;
+       size_t vlen;
+       hash_random_t *rv;
+       hash_accum_t overflow_limit;
+
+       REQUIRE(mctx != NULL);
+       REQUIRE(hctxp != NULL && *hctxp == NULL);
+
+       /*
+        * Overflow check.  Since our implementation only does a modulo
+        * operation at the last stage of hash calculation, the accumulator
+        * must not overflow.
+        */
+       overflow_limit =
+               1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8);
+       if (overflow_limit < (limit + 1) * 0xff)
+               return (ISC_R_RANGE);
+
+       hctx = isc_mem_get(mctx, sizeof(isc_hash_t));
+       if (hctx == NULL)
+               return (ISC_R_NOMEMORY);
+
+       vlen = sizeof(hash_random_t) * (limit + 1);
+       rv = isc_mem_get(mctx, vlen);
+       if (rv == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto errout;
+       }
+
+       /*
+        * We need a lock.
+        */
+       result = isc_mutex_init(&hctx->lock);
+       if (result != ISC_R_SUCCESS)
+               goto errout;
+
+       /*
+        * From here down, no failures will/can occur.
+        */
+       hctx->magic = HASH_MAGIC;
+       hctx->mctx = NULL;
+       isc_mem_attach(mctx, &hctx->mctx);
+       hctx->initialized = ISC_FALSE;
+       result = isc_refcount_init(&hctx->refcnt, 1);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup_lock;
+       hctx->entropy = NULL;
+       hctx->limit = limit;
+       hctx->vectorlen = vlen;
+       hctx->rndvector = rv;
+
+       if (entropy != NULL)
+               isc_entropy_attach(entropy, &hctx->entropy);
+
+       *hctxp = hctx;
+       return (ISC_R_SUCCESS);
+
+ cleanup_lock:
+       DESTROYLOCK(&hctx->lock);
+ errout:
+       isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
+       if (rv != NULL)
+               isc_mem_put(mctx, rv, vlen);
+
+       return (result);
+}
+
+static void
+initialize_lock(void) {
+       RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(mctx != NULL);
+       INSIST(hash == NULL);
+
+       RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS);
+
+       LOCK(&createlock);
+
+       if (hash == NULL)
+               result = isc_hash_ctxcreate(mctx, entropy, limit, &hash);
+
+       UNLOCK(&createlock);
+
+       return (result);
+}
+
+void
+isc_hash_ctxinit(isc_hash_t *hctx) {
+       isc_result_t result;
+
+       LOCK(&hctx->lock);
+
+       if (hctx->initialized == ISC_TRUE)
+               goto out;
+
+       if (hctx->entropy) {
+               result = isc_entropy_getdata(hctx->entropy,
+                                            hctx->rndvector, hctx->vectorlen,
+                                            NULL, 0);
+               INSIST(result == ISC_R_SUCCESS);
+       } else {
+               isc_uint32_t pr;
+               unsigned int i, copylen;
+               unsigned char *p;
+
+               p = (unsigned char *)hctx->rndvector;
+               for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) {
+                       isc_random_get(&pr);
+                       if (i + sizeof(pr) <= hctx->vectorlen)
+                               copylen = sizeof(pr);
+                       else
+                               copylen = hctx->vectorlen - i;
+
+                       memcpy(p, &pr, copylen);
+               }
+               INSIST(p == (unsigned char *)hctx->rndvector +
+                      hctx->vectorlen);
+       }
+
+       hctx->initialized = ISC_TRUE;
+
+ out:
+       UNLOCK(&hctx->lock);
+}
+
+void
+isc_hash_init() {
+       INSIST(hash != NULL && VALID_HASH(hash));
+
+       isc_hash_ctxinit(hash);
+}
+
+void
+isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) {
+       REQUIRE(VALID_HASH(hctx));
+       REQUIRE(hctxp != NULL && *hctxp == NULL);
+
+       isc_refcount_increment(&hctx->refcnt, NULL);
+       *hctxp = hctx;
+}
+
+static void
+destroy(isc_hash_t **hctxp) {
+       isc_hash_t *hctx;
+       isc_mem_t *mctx;
+
+       REQUIRE(hctxp != NULL && *hctxp != NULL);
+       hctx = *hctxp;
+       *hctxp = NULL;
+
+       LOCK(&hctx->lock);
+
+       isc_refcount_destroy(&hctx->refcnt);
+
+       mctx = hctx->mctx;
+       if (hctx->entropy != NULL)
+               isc_entropy_detach(&hctx->entropy);
+       if (hctx->rndvector != NULL)
+               isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen);
+
+       UNLOCK(&hctx->lock);
+
+       DESTROYLOCK(&hctx->lock);
+
+       memset(hctx, 0, sizeof(isc_hash_t));
+       isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
+       isc_mem_detach(&mctx);
+}
+
+void
+isc_hash_ctxdetach(isc_hash_t **hctxp) {
+       isc_hash_t *hctx;
+       unsigned int refs;
+
+       REQUIRE(hctxp != NULL && VALID_HASH(*hctxp));
+       hctx = *hctxp;
+
+       isc_refcount_decrement(&hctx->refcnt, &refs);
+       if (refs == 0)
+               destroy(&hctx);
+
+       *hctxp = NULL;
+}
+
+void
+isc_hash_destroy() {
+       unsigned int refs;
+
+       INSIST(hash != NULL && VALID_HASH(hash));
+
+       isc_refcount_decrement(&hash->refcnt, &refs);
+       INSIST(refs == 0);
+
+       destroy(&hash);
+}
+
+static inline unsigned int
+hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen,
+         isc_boolean_t case_sensitive)
+{
+       hash_accum_t partial_sum = 0;
+       hash_random_t *p = hctx->rndvector;
+       unsigned int i = 0;
+
+       /* Make it sure that the hash context is initialized. */
+       if (hctx->initialized == ISC_FALSE)
+               isc_hash_ctxinit(hctx);
+
+       if (case_sensitive) {
+               for (i = 0; i < keylen; i++)
+                       partial_sum += key[i] * (hash_accum_t)p[i];
+       } else {
+               for (i = 0; i < keylen; i++)
+                       partial_sum += maptolower[key[i]] * (hash_accum_t)p[i];
+       }
+
+       partial_sum += p[i];
+
+       return ((unsigned int)(partial_sum % PRIME32));
+}
+
+unsigned int
+isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
+                unsigned int keylen, isc_boolean_t case_sensitive)
+{
+       REQUIRE(hctx != NULL && VALID_HASH(hctx));
+       REQUIRE(keylen <= hctx->limit);
+
+       return (hash_calc(hctx, key, keylen, case_sensitive));
+}
+
+unsigned int
+isc_hash_calc(const unsigned char *key, unsigned int keylen,
+             isc_boolean_t case_sensitive)
+{
+       INSIST(hash != NULL && VALID_HASH(hash));
+       REQUIRE(keylen <= hash->limit);
+
+       return (hash_calc(hash, key, keylen, case_sensitive));
+}
diff --git a/lib/isc/heap.c b/lib/isc/heap.c
new file mode 100644 (file)
index 0000000..91d78c0
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: heap.c,v 1.37 2007/10/19 17:15:53 explorer Exp $ */
+
+/*! \file
+ * Heap implementation of priority queues adapted from the following:
+ *
+ *     \li "Introduction to Algorithms," Cormen, Leiserson, and Rivest,
+ *     MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
+ *
+ *     \li "Algorithms," Second Edition, Sedgewick, Addison-Wesley, 1988,
+ *     ISBN 0-201-06673-4, chapter 11.
+ */
+
+#include <config.h>
+
+#include <isc/heap.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/string.h>                /* Required for memcpy. */
+#include <isc/util.h>
+
+/*@{*/
+/*%
+ * Note: to make heap_parent and heap_left easy to compute, the first
+ * element of the heap array is not used; i.e. heap subscripts are 1-based,
+ * not 0-based.  The parent is index/2, and the left-child is index*2.
+ * The right child is index*2+1.
+ */
+#define heap_parent(i)                 ((i) >> 1)
+#define heap_left(i)                   ((i) << 1)
+/*@}*/
+
+#define SIZE_INCREMENT                 1024
+
+#define HEAP_MAGIC                     ISC_MAGIC('H', 'E', 'A', 'P')
+#define VALID_HEAP(h)                  ISC_MAGIC_VALID(h, HEAP_MAGIC)
+
+/*%
+ * When the heap is in a consistent state, the following invariant
+ * holds true: for every element i > 1, heap_parent(i) has a priority
+ * higher than or equal to that of i.
+ */
+#define HEAPCONDITION(i) ((i) == 1 || \
+                         ! heap->compare(heap->array[(i)], \
+                                         heap->array[heap_parent(i)]))
+
+/*% ISC heap structure. */
+struct isc_heap {
+       unsigned int                    magic;
+       isc_mem_t *                     mctx;
+       unsigned int                    size;
+       unsigned int                    size_increment;
+       unsigned int                    last;
+       void                            **array;
+       isc_heapcompare_t               compare;
+       isc_heapindex_t                 index;
+};
+
+isc_result_t
+isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare,
+               isc_heapindex_t index, unsigned int size_increment,
+               isc_heap_t **heapp)
+{
+       isc_heap_t *heap;
+
+       REQUIRE(heapp != NULL && *heapp == NULL);
+       REQUIRE(compare != NULL);
+
+       heap = isc_mem_get(mctx, sizeof(*heap));
+       if (heap == NULL)
+               return (ISC_R_NOMEMORY);
+       heap->magic = HEAP_MAGIC;
+       heap->mctx = mctx;
+       heap->size = 0;
+       if (size_increment == 0)
+               heap->size_increment = SIZE_INCREMENT;
+       else
+               heap->size_increment = size_increment;
+       heap->last = 0;
+       heap->array = NULL;
+       heap->compare = compare;
+       heap->index = index;
+
+       *heapp = heap;
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_heap_destroy(isc_heap_t **heapp) {
+       isc_heap_t *heap;
+
+       REQUIRE(heapp != NULL);
+       heap = *heapp;
+       REQUIRE(VALID_HEAP(heap));
+
+       if (heap->array != NULL)
+               isc_mem_put(heap->mctx, heap->array,
+                           heap->size * sizeof(void *));
+       heap->magic = 0;
+       isc_mem_put(heap->mctx, heap, sizeof(*heap));
+
+       *heapp = NULL;
+}
+
+static isc_boolean_t
+resize(isc_heap_t *heap) {
+       void **new_array;
+       size_t new_size;
+
+       REQUIRE(VALID_HEAP(heap));
+
+       new_size = heap->size + heap->size_increment;
+       new_array = isc_mem_get(heap->mctx, new_size * sizeof(void *));
+       if (new_array == NULL)
+               return (ISC_FALSE);
+       if (heap->array != NULL) {
+               memcpy(new_array, heap->array, heap->size * sizeof(void *));
+               isc_mem_put(heap->mctx, heap->array,
+                           heap->size * sizeof(void *));
+       }
+       heap->size = new_size;
+       heap->array = new_array;
+
+       return (ISC_TRUE);
+}
+
+static void
+float_up(isc_heap_t *heap, unsigned int i, void *elt) {
+       unsigned int p;
+
+       for (p = heap_parent(i) ;
+            i > 1 && heap->compare(elt, heap->array[p]) ;
+            i = p, p = heap_parent(i)) {
+               heap->array[i] = heap->array[p];
+               if (heap->index != NULL)
+                       (heap->index)(heap->array[i], i);
+       }
+       heap->array[i] = elt;
+       if (heap->index != NULL)
+               (heap->index)(heap->array[i], i);
+
+       INSIST(HEAPCONDITION(i));
+}
+
+static void
+sink_down(isc_heap_t *heap, unsigned int i, void *elt) {
+       unsigned int j, size, half_size;
+       size = heap->last;
+       half_size = size / 2;
+       while (i <= half_size) {
+               /* Find the smallest of the (at most) two children. */
+               j = heap_left(i);
+               if (j < size && heap->compare(heap->array[j+1],
+                                             heap->array[j]))
+                       j++;
+               if (heap->compare(elt, heap->array[j]))
+                       break;
+               heap->array[i] = heap->array[j];
+               if (heap->index != NULL)
+                       (heap->index)(heap->array[i], i);
+               i = j;
+       }
+       heap->array[i] = elt;
+       if (heap->index != NULL)
+               (heap->index)(heap->array[i], i);
+
+       INSIST(HEAPCONDITION(i));
+}
+
+isc_result_t
+isc_heap_insert(isc_heap_t *heap, void *elt) {
+       unsigned int i;
+
+       REQUIRE(VALID_HEAP(heap));
+
+       i = ++heap->last;
+       if (heap->last >= heap->size && !resize(heap))
+               return (ISC_R_NOMEMORY);
+
+       float_up(heap, i, elt);
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_heap_delete(isc_heap_t *heap, unsigned int index) {
+       void *elt;
+       isc_boolean_t less;
+
+       REQUIRE(VALID_HEAP(heap));
+       REQUIRE(index >= 1 && index <= heap->last);
+
+       if (index == heap->last) {
+               heap->array[heap->last] = NULL;
+               heap->last--;
+       } else {
+               elt = heap->array[heap->last];
+               heap->array[heap->last] = NULL;
+               heap->last--;
+
+               less = heap->compare(elt, heap->array[index]);
+               heap->array[index] = elt;
+               if (less)
+                       float_up(heap, index, heap->array[index]);
+               else
+                       sink_down(heap, index, heap->array[index]);
+       }
+}
+
+void
+isc_heap_increased(isc_heap_t *heap, unsigned int index) {
+       REQUIRE(VALID_HEAP(heap));
+       REQUIRE(index >= 1 && index <= heap->last);
+
+       float_up(heap, index, heap->array[index]);
+}
+
+void
+isc_heap_decreased(isc_heap_t *heap, unsigned int index) {
+       REQUIRE(VALID_HEAP(heap));
+       REQUIRE(index >= 1 && index <= heap->last);
+
+       sink_down(heap, index, heap->array[index]);
+}
+
+void *
+isc_heap_element(isc_heap_t *heap, unsigned int index) {
+       REQUIRE(VALID_HEAP(heap));
+       REQUIRE(index >= 1);
+
+       if (index <= heap->last)
+               return (heap->array[index]);
+       return (NULL);
+}
+
+void
+isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap) {
+       unsigned int i;
+
+       REQUIRE(VALID_HEAP(heap));
+       REQUIRE(action != NULL);
+
+       for (i = 1 ; i <= heap->last ; i++)
+               (action)(heap->array[i], uap);
+}
diff --git a/lib/isc/hex.c b/lib/isc/hex.c
new file mode 100644 (file)
index 0000000..3fa0e69
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hex.c,v 1.20 2008/09/25 04:02:39 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <isc/buffer.h>
+#include <isc/hex.h>
+#include <isc/lex.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#define RETERR(x) do { \
+       isc_result_t _r = (x); \
+       if (_r != ISC_R_SUCCESS) \
+               return (_r); \
+       } while (0)
+
+
+/*
+ * BEW: These static functions are copied from lib/dns/rdata.c.
+ */
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target);
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
+
+static const char hex[] = "0123456789ABCDEF";
+
+isc_result_t
+isc_hex_totext(isc_region_t *source, int wordlength,
+              const char *wordbreak, isc_buffer_t *target)
+{
+       char buf[3];
+       unsigned int loops = 0;
+
+       if (wordlength < 2)
+               wordlength = 2;
+
+       memset(buf, 0, sizeof(buf));
+       while (source->length > 0) {
+               buf[0] = hex[(source->base[0] >> 4) & 0xf];
+               buf[1] = hex[(source->base[0]) & 0xf];
+               RETERR(str_totext(buf, target));
+               isc_region_consume(source, 1);
+
+               loops++;
+               if (source->length != 0 &&
+                   (int)((loops + 1) * 2) >= wordlength)
+               {
+                       loops = 0;
+                       RETERR(str_totext(wordbreak, target));
+               }
+       }
+       return (ISC_R_SUCCESS);
+}
+
+/*%
+ * State of a hex decoding process in progress.
+ */
+typedef struct {
+       int length;             /*%< Desired length of binary data or -1 */
+       isc_buffer_t *target;   /*%< Buffer for resulting binary data */
+       int digits;             /*%< Number of buffered hex digits */
+       int val[2];
+} hex_decode_ctx_t;
+
+static inline void
+hex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target)
+{
+       ctx->digits = 0;
+       ctx->length = length;
+       ctx->target = target;
+}
+
+static inline isc_result_t
+hex_decode_char(hex_decode_ctx_t *ctx, int c) {
+       char *s;
+
+       if ((s = strchr(hex, toupper(c))) == NULL)
+               return (ISC_R_BADHEX);
+       ctx->val[ctx->digits++] = s - hex;
+       if (ctx->digits == 2) {
+               unsigned char num;
+
+               num = (ctx->val[0] << 4) + (ctx->val[1]);
+               RETERR(mem_tobuffer(ctx->target, &num, 1));
+               if (ctx->length >= 0) {
+                       if (ctx->length == 0)
+                               return (ISC_R_BADHEX);
+                       else
+                               ctx->length -= 1;
+               }
+               ctx->digits = 0;
+       }
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+hex_decode_finish(hex_decode_ctx_t *ctx) {
+       if (ctx->length > 0)
+               return (ISC_R_UNEXPECTEDEND);
+       if (ctx->digits != 0)
+               return (ISC_R_BADHEX);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
+       hex_decode_ctx_t ctx;
+       isc_textregion_t *tr;
+       isc_token_t token;
+       isc_boolean_t eol;
+
+       hex_decode_init(&ctx, length, target);
+
+       while (ctx.length != 0) {
+               unsigned int i;
+
+               if (length > 0)
+                       eol = ISC_FALSE;
+               else
+                       eol = ISC_TRUE;
+               RETERR(isc_lex_getmastertoken(lexer, &token,
+                                             isc_tokentype_string, eol));
+               if (token.type != isc_tokentype_string)
+                       break;
+               tr = &token.value.as_textregion;
+               for (i = 0; i < tr->length; i++)
+                       RETERR(hex_decode_char(&ctx, tr->base[i]));
+       }
+       if (ctx.length < 0)
+               isc_lex_ungettoken(lexer, &token);
+       RETERR(hex_decode_finish(&ctx));
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_hex_decodestring(const char *cstr, isc_buffer_t *target) {
+       hex_decode_ctx_t ctx;
+
+       hex_decode_init(&ctx, -1, target);
+       for (;;) {
+               int c = *cstr++;
+               if (c == '\0')
+                       break;
+               if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
+                       continue;
+               RETERR(hex_decode_char(&ctx, c));
+       }
+       RETERR(hex_decode_finish(&ctx));
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+str_totext(const char *source, isc_buffer_t *target) {
+       unsigned int l;
+       isc_region_t region;
+
+       isc_buffer_availableregion(target, &region);
+       l = strlen(source);
+
+       if (l > region.length)
+               return (ISC_R_NOSPACE);
+
+       memcpy(region.base, source, l);
+       isc_buffer_add(target, l);
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
+       isc_region_t tr;
+
+       isc_buffer_availableregion(target, &tr);
+       if (length > tr.length)
+               return (ISC_R_NOSPACE);
+       memcpy(tr.base, base, length);
+       isc_buffer_add(target, length);
+       return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/hmacmd5.c b/lib/isc/hmacmd5.c
new file mode 100644 (file)
index 0000000..63853dc
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hmacmd5.c,v 1.14 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file
+ * This code implements the HMAC-MD5 keyed hash algorithm
+ * described in RFC2104.
+ */
+
+#include "config.h"
+
+#include <isc/assertions.h>
+#include <isc/hmacmd5.h>
+#include <isc/md5.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#define PADLEN 64
+#define IPAD 0x36
+#define OPAD 0x5C
+
+/*!
+ * Start HMAC-MD5 process.  Initialize an md5 context and digest the key.
+ */
+void
+isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
+                unsigned int len)
+{
+       unsigned char ipad[PADLEN];
+       int i;
+
+       memset(ctx->key, 0, sizeof(ctx->key));
+       if (len > sizeof(ctx->key)) {
+               isc_md5_t md5ctx;
+               isc_md5_init(&md5ctx);
+               isc_md5_update(&md5ctx, key, len);
+               isc_md5_final(&md5ctx, ctx->key);
+       } else
+               memcpy(ctx->key, key, len);
+
+       isc_md5_init(&ctx->md5ctx);
+       memset(ipad, IPAD, sizeof(ipad));
+       for (i = 0; i < PADLEN; i++)
+               ipad[i] ^= ctx->key[i];
+       isc_md5_update(&ctx->md5ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
+       isc_md5_invalidate(&ctx->md5ctx);
+       memset(ctx->key, 0, sizeof(ctx->key));
+}
+
+/*!
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
+                  unsigned int len)
+{
+       isc_md5_update(&ctx->md5ctx, buf, len);
+}
+
+/*!
+ * Compute signature - finalize MD5 operation and reapply MD5.
+ */
+void
+isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
+       unsigned char opad[PADLEN];
+       int i;
+
+       isc_md5_final(&ctx->md5ctx, digest);
+
+       memset(opad, OPAD, sizeof(opad));
+       for (i = 0; i < PADLEN; i++)
+               opad[i] ^= ctx->key[i];
+
+       isc_md5_init(&ctx->md5ctx);
+       isc_md5_update(&ctx->md5ctx, opad, sizeof(opad));
+       isc_md5_update(&ctx->md5ctx, digest, ISC_MD5_DIGESTLENGTH);
+       isc_md5_final(&ctx->md5ctx, digest);
+       isc_hmacmd5_invalidate(ctx);
+}
+
+/*!
+ * Verify signature - finalize MD5 operation and reapply MD5, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest) {
+       return (isc_hmacmd5_verify2(ctx, digest, ISC_MD5_DIGESTLENGTH));
+}
+
+isc_boolean_t
+isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char newdigest[ISC_MD5_DIGESTLENGTH];
+
+       REQUIRE(len <= ISC_MD5_DIGESTLENGTH);
+       isc_hmacmd5_sign(ctx, newdigest);
+       return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
diff --git a/lib/isc/hmacsha.c b/lib/isc/hmacsha.c
new file mode 100644 (file)
index 0000000..dfcd8bf
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2005-2007  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hmacsha.c,v 1.8 2007/08/27 03:27:53 marka Exp $ */
+
+/*
+ * This code implements the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, HMAC-SHA384
+ * and HMAC-SHA512 keyed hash algorithm described in RFC 2104 and
+ * draft-ietf-dnsext-tsig-sha-01.txt.
+ */
+
+#include "config.h"
+
+#include <isc/assertions.h>
+#include <isc/hmacsha.h>
+#include <isc/sha1.h>
+#include <isc/sha2.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#define IPAD 0x36
+#define OPAD 0x5C
+
+/*
+ * Start HMAC-SHA1 process.  Initialize an sha1 context and digest the key.
+ */
+void
+isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
+                 unsigned int len)
+{
+       unsigned char ipad[ISC_SHA1_BLOCK_LENGTH];
+       unsigned int i;
+
+       memset(ctx->key, 0, sizeof(ctx->key));
+       if (len > sizeof(ctx->key)) {
+               isc_sha1_t sha1ctx;
+               isc_sha1_init(&sha1ctx);
+               isc_sha1_update(&sha1ctx, key, len);
+               isc_sha1_final(&sha1ctx, ctx->key);
+       } else
+               memcpy(ctx->key, key, len);
+
+       isc_sha1_init(&ctx->sha1ctx);
+       memset(ipad, IPAD, sizeof(ipad));
+       for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++)
+               ipad[i] ^= ctx->key[i];
+       isc_sha1_update(&ctx->sha1ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) {
+       isc_sha1_invalidate(&ctx->sha1ctx);
+       memset(ctx->key, 0, sizeof(ctx->key));
+       memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
+                  unsigned int len)
+{
+       isc_sha1_update(&ctx->sha1ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA1 operation and reapply SHA1.
+ */
+void
+isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char opad[ISC_SHA1_BLOCK_LENGTH];
+       unsigned char newdigest[ISC_SHA1_DIGESTLENGTH];
+       unsigned int i;
+
+       REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
+       isc_sha1_final(&ctx->sha1ctx, newdigest);
+
+       memset(opad, OPAD, sizeof(opad));
+       for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++)
+               opad[i] ^= ctx->key[i];
+
+       isc_sha1_init(&ctx->sha1ctx);
+       isc_sha1_update(&ctx->sha1ctx, opad, sizeof(opad));
+       isc_sha1_update(&ctx->sha1ctx, newdigest, ISC_SHA1_DIGESTLENGTH);
+       isc_sha1_final(&ctx->sha1ctx, newdigest);
+       isc_hmacsha1_invalidate(ctx);
+       memcpy(digest, newdigest, len);
+       memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA1 operation and reapply SHA1, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char newdigest[ISC_SHA1_DIGESTLENGTH];
+
+       REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
+       isc_hmacsha1_sign(ctx, newdigest, ISC_SHA1_DIGESTLENGTH);
+       return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
+
+/*
+ * Start HMAC-SHA224 process.  Initialize an sha224 context and digest the key.
+ */
+void
+isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
+                   unsigned int len)
+{
+       unsigned char ipad[ISC_SHA224_BLOCK_LENGTH];
+       unsigned int i;
+
+       memset(ctx->key, 0, sizeof(ctx->key));
+       if (len > sizeof(ctx->key)) {
+               isc_sha224_t sha224ctx;
+               isc_sha224_init(&sha224ctx);
+               isc_sha224_update(&sha224ctx, key, len);
+               isc_sha224_final(ctx->key, &sha224ctx);
+       } else
+               memcpy(ctx->key, key, len);
+
+       isc_sha224_init(&ctx->sha224ctx);
+       memset(ipad, IPAD, sizeof(ipad));
+       for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++)
+               ipad[i] ^= ctx->key[i];
+       isc_sha224_update(&ctx->sha224ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) {
+       memset(ctx->key, 0, sizeof(ctx->key));
+       memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
+                  unsigned int len)
+{
+       isc_sha224_update(&ctx->sha224ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA224 operation and reapply SHA224.
+ */
+void
+isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char opad[ISC_SHA224_BLOCK_LENGTH];
+       unsigned char newdigest[ISC_SHA224_DIGESTLENGTH];
+       unsigned int i;
+
+       REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
+       isc_sha224_final(newdigest, &ctx->sha224ctx);
+
+       memset(opad, OPAD, sizeof(opad));
+       for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++)
+               opad[i] ^= ctx->key[i];
+
+       isc_sha224_init(&ctx->sha224ctx);
+       isc_sha224_update(&ctx->sha224ctx, opad, sizeof(opad));
+       isc_sha224_update(&ctx->sha224ctx, newdigest, ISC_SHA224_DIGESTLENGTH);
+       isc_sha224_final(newdigest, &ctx->sha224ctx);
+       memcpy(digest, newdigest, len);
+       memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA224 operation and reapply SHA224, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char newdigest[ISC_SHA224_DIGESTLENGTH];
+
+       REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
+       isc_hmacsha224_sign(ctx, newdigest, ISC_SHA224_DIGESTLENGTH);
+       return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
+
+/*
+ * Start HMAC-SHA256 process.  Initialize an sha256 context and digest the key.
+ */
+void
+isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
+                   unsigned int len)
+{
+       unsigned char ipad[ISC_SHA256_BLOCK_LENGTH];
+       unsigned int i;
+
+       memset(ctx->key, 0, sizeof(ctx->key));
+       if (len > sizeof(ctx->key)) {
+               isc_sha256_t sha256ctx;
+               isc_sha256_init(&sha256ctx);
+               isc_sha256_update(&sha256ctx, key, len);
+               isc_sha256_final(ctx->key, &sha256ctx);
+       } else
+               memcpy(ctx->key, key, len);
+
+       isc_sha256_init(&ctx->sha256ctx);
+       memset(ipad, IPAD, sizeof(ipad));
+       for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++)
+               ipad[i] ^= ctx->key[i];
+       isc_sha256_update(&ctx->sha256ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) {
+       memset(ctx->key, 0, sizeof(ctx->key));
+       memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
+                  unsigned int len)
+{
+       isc_sha256_update(&ctx->sha256ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA256 operation and reapply SHA256.
+ */
+void
+isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char opad[ISC_SHA256_BLOCK_LENGTH];
+       unsigned char newdigest[ISC_SHA256_DIGESTLENGTH];
+       unsigned int i;
+
+       REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
+       isc_sha256_final(newdigest, &ctx->sha256ctx);
+
+       memset(opad, OPAD, sizeof(opad));
+       for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++)
+               opad[i] ^= ctx->key[i];
+
+       isc_sha256_init(&ctx->sha256ctx);
+       isc_sha256_update(&ctx->sha256ctx, opad, sizeof(opad));
+       isc_sha256_update(&ctx->sha256ctx, newdigest, ISC_SHA256_DIGESTLENGTH);
+       isc_sha256_final(newdigest, &ctx->sha256ctx);
+       memcpy(digest, newdigest, len);
+       memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA256 operation and reapply SHA256, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char newdigest[ISC_SHA256_DIGESTLENGTH];
+
+       REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
+       isc_hmacsha256_sign(ctx, newdigest, ISC_SHA256_DIGESTLENGTH);
+       return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
+
+/*
+ * Start HMAC-SHA384 process.  Initialize an sha384 context and digest the key.
+ */
+void
+isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
+                   unsigned int len)
+{
+       unsigned char ipad[ISC_SHA384_BLOCK_LENGTH];
+       unsigned int i;
+
+       memset(ctx->key, 0, sizeof(ctx->key));
+       if (len > sizeof(ctx->key)) {
+               isc_sha384_t sha384ctx;
+               isc_sha384_init(&sha384ctx);
+               isc_sha384_update(&sha384ctx, key, len);
+               isc_sha384_final(ctx->key, &sha384ctx);
+       } else
+               memcpy(ctx->key, key, len);
+
+       isc_sha384_init(&ctx->sha384ctx);
+       memset(ipad, IPAD, sizeof(ipad));
+       for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++)
+               ipad[i] ^= ctx->key[i];
+       isc_sha384_update(&ctx->sha384ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) {
+       memset(ctx->key, 0, sizeof(ctx->key));
+       memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
+                  unsigned int len)
+{
+       isc_sha384_update(&ctx->sha384ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA384 operation and reapply SHA384.
+ */
+void
+isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char opad[ISC_SHA384_BLOCK_LENGTH];
+       unsigned char newdigest[ISC_SHA384_DIGESTLENGTH];
+       unsigned int i;
+
+       REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
+       isc_sha384_final(newdigest, &ctx->sha384ctx);
+
+       memset(opad, OPAD, sizeof(opad));
+       for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++)
+               opad[i] ^= ctx->key[i];
+
+       isc_sha384_init(&ctx->sha384ctx);
+       isc_sha384_update(&ctx->sha384ctx, opad, sizeof(opad));
+       isc_sha384_update(&ctx->sha384ctx, newdigest, ISC_SHA384_DIGESTLENGTH);
+       isc_sha384_final(newdigest, &ctx->sha384ctx);
+       memcpy(digest, newdigest, len);
+       memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA384 operation and reapply SHA384, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char newdigest[ISC_SHA384_DIGESTLENGTH];
+
+       REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
+       isc_hmacsha384_sign(ctx, newdigest, ISC_SHA384_DIGESTLENGTH);
+       return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
+
+/*
+ * Start HMAC-SHA512 process.  Initialize an sha512 context and digest the key.
+ */
+void
+isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
+                   unsigned int len)
+{
+       unsigned char ipad[ISC_SHA512_BLOCK_LENGTH];
+       unsigned int i;
+
+       memset(ctx->key, 0, sizeof(ctx->key));
+       if (len > sizeof(ctx->key)) {
+               isc_sha512_t sha512ctx;
+               isc_sha512_init(&sha512ctx);
+               isc_sha512_update(&sha512ctx, key, len);
+               isc_sha512_final(ctx->key, &sha512ctx);
+       } else
+               memcpy(ctx->key, key, len);
+
+       isc_sha512_init(&ctx->sha512ctx);
+       memset(ipad, IPAD, sizeof(ipad));
+       for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++)
+               ipad[i] ^= ctx->key[i];
+       isc_sha512_update(&ctx->sha512ctx, ipad, sizeof(ipad));
+}
+
+void
+isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) {
+       memset(ctx->key, 0, sizeof(ctx->key));
+       memset(ctx, 0, sizeof(ctx));
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
+                  unsigned int len)
+{
+       isc_sha512_update(&ctx->sha512ctx, buf, len);
+}
+
+/*
+ * Compute signature - finalize SHA512 operation and reapply SHA512.
+ */
+void
+isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char opad[ISC_SHA512_BLOCK_LENGTH];
+       unsigned char newdigest[ISC_SHA512_DIGESTLENGTH];
+       unsigned int i;
+
+       REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
+       isc_sha512_final(newdigest, &ctx->sha512ctx);
+
+       memset(opad, OPAD, sizeof(opad));
+       for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++)
+               opad[i] ^= ctx->key[i];
+
+       isc_sha512_init(&ctx->sha512ctx);
+       isc_sha512_update(&ctx->sha512ctx, opad, sizeof(opad));
+       isc_sha512_update(&ctx->sha512ctx, newdigest, ISC_SHA512_DIGESTLENGTH);
+       isc_sha512_final(newdigest, &ctx->sha512ctx);
+       memcpy(digest, newdigest, len);
+       memset(newdigest, 0, sizeof(newdigest));
+}
+
+/*
+ * Verify signature - finalize SHA512 operation and reapply SHA512, then
+ * compare to the supplied digest.
+ */
+isc_boolean_t
+isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+       unsigned char newdigest[ISC_SHA512_DIGESTLENGTH];
+
+       REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
+       isc_hmacsha512_sign(ctx, newdigest, ISC_SHA512_DIGESTLENGTH);
+       return (ISC_TF(memcmp(digest, newdigest, len) == 0));
+}
diff --git a/lib/isc/httpd.c b/lib/isc/httpd.c
new file mode 100644 (file)
index 0000000..fa31325
--- /dev/null
@@ -0,0 +1,987 @@
+/*
+ * Copyright (C) 2006-2008  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: httpd.c,v 1.16 2008/08/08 05:06:49 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/buffer.h>
+#include <isc/httpd.h>
+#include <isc/mem.h>
+#include <isc/socket.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <string.h>
+
+/*%
+ * TODO:
+ *
+ *  o  Put in better checks to make certain things are passed in correctly.
+ *     This includes a magic number for externally-visible structures,
+ *     checking for NULL-ness before dereferencing, etc.
+ *  o  Make the URL processing external functions which will fill-in a buffer
+ *     structure we provide, or return an error and we will render a generic
+ *     page and close the client.
+ */
+
+#define MSHUTTINGDOWN(cm) ((cm->flags & ISC_HTTPDMGR_FLAGSHUTTINGDOWN) != 0)
+#define MSETSHUTTINGDOWN(cm) (cm->flags |= ISC_HTTPDMGR_FLAGSHUTTINGDOWN)
+
+#ifdef DEBUG_HTTPD
+#define ENTER(x) do { fprintf(stderr, "ENTER %s\n", (x)); } while (0)
+#define EXIT(x) do { fprintf(stderr, "EXIT %s\n", (x)); } while (0)
+#define NOTICE(x) do { fprintf(stderr, "NOTICE %s\n", (x)); } while (0)
+#else
+#define ENTER(x) do { } while(0)
+#define EXIT(x) do { } while(0)
+#define NOTICE(x) do { } while(0)
+#endif
+
+#define HTTP_RECVLEN                   1024
+#define HTTP_SENDGROW                  1024
+#define HTTP_SEND_MAXLEN               10240
+
+/*%
+ * HTTP urls.  These are the URLs we manage, and the function to call to
+ * provide the data for it.  We pass in the base url (so the same function
+ * can handle multiple requests), and a structure to fill in to return a
+ * result to the client.  We also pass in a pointer to be filled in for
+ * the data cleanup function.
+ */
+struct isc_httpdurl {
+       char                           *url;
+       isc_httpdaction_t              *action;
+       void                           *action_arg;
+       ISC_LINK(isc_httpdurl_t)        link;
+};
+
+#define HTTPD_CLOSE            0x0001 /* Got a Connection: close header */
+#define HTTPD_FOUNDHOST                0x0002 /* Got a Host: header */
+
+/*% http client */
+struct isc_httpd {
+       isc_httpdmgr_t         *mgr;            /*%< our parent */
+       ISC_LINK(isc_httpd_t)   link;
+       unsigned int            state;
+       isc_socket_t            *sock;
+
+       /*%
+        * Received data state.
+        */
+       char                    recvbuf[HTTP_RECVLEN]; /*%< receive buffer */
+       isc_uint32_t            recvlen;        /*%< length recv'd */
+       unsigned int            method;
+       char                   *url;
+       char                   *querystring;
+       char                   *protocol;
+
+       /*
+        * Flags on the httpd client.
+        */
+       int                     flags;
+
+       /*%
+        * Transmit data state.
+        *
+        * This is the data buffer we will transmit.
+        *
+        * This free function pointer is filled in by the rendering function
+        * we call.  The free function is called after the data is transmitted
+        * to the client.
+        *
+        * The bufflist is the list of buffers we are currently transmitting.
+        * The headerdata is where we render our headers to.  If we run out of
+        * space when rendering a header, we will change the size of our
+        * buffer.  We will not free it until we are finished, and will
+        * allocate an additional HTTP_SENDGROW bytes per header space grow.
+        *
+        * We currently use two buffers total, one for the headers (which
+        * we manage) and another for the client to fill in (which it manages,
+        * it provides the space for it, etc) -- we will pass that buffer
+        * structure back to the caller, who is responsible for managing the
+        * space it may have allocated as backing store for it.  This second
+        * buffer is bodybuffer, and we only allocate the buffer itself, not
+        * the backing store.
+        */
+       isc_bufferlist_t        bufflist;
+       char                   *headerdata; /*%< send header buf */
+       unsigned int            headerlen;  /*%< current header buffer size */
+       isc_buffer_t            headerbuffer;
+
+       const char             *mimetype;
+       unsigned int            retcode;
+       const char             *retmsg;
+       isc_buffer_t            bodybuffer;
+       isc_httpdfree_t        *freecb;
+       void                   *freecb_arg;
+};
+
+/*% lightweight socket manager for httpd output */
+struct isc_httpdmgr {
+       isc_mem_t              *mctx;
+       isc_socket_t           *sock;           /*%< listening socket */
+       isc_task_t             *task;           /*%< owning task */
+       isc_timermgr_t         *timermgr;
+
+       isc_httpdclientok_t    *client_ok;      /*%< client validator */
+       isc_httpdondestroy_t   *ondestroy;      /*%< cleanup callback */
+       void                   *cb_arg;         /*%< argument for the above */
+
+       unsigned int            flags;
+       ISC_LIST(isc_httpd_t)   running;        /*%< running clients */
+
+       isc_mutex_t             lock;
+
+       ISC_LIST(isc_httpdurl_t) urls;          /*%< urls we manage */
+       isc_httpdaction_t      *render_404;
+};
+
+/*%
+ * HTTP methods.
+ */
+#define ISC_HTTPD_METHODUNKNOWN        0
+#define ISC_HTTPD_METHODGET    1
+#define ISC_HTTPD_METHODPOST   2
+
+/*%
+ * Client states.
+ *
+ * _IDLE       The client is not doing anything at all.  This state should
+ *             only occur just after creation, and just before being
+ *             destroyed.
+ *
+ * _RECV       The client is waiting for data after issuing a socket recv().
+ *
+ * _RECVDONE   Data has been received, and is being processed.
+ *
+ * _SEND       All data for a response has completed, and a reply was
+ *             sent via a socket send() call.
+ *
+ * _SENDDONE   Send is completed.
+ *
+ * Badly formatted state table:
+ *
+ *     IDLE -> RECV when client has a recv() queued.
+ *
+ *     RECV -> RECVDONE when recvdone event received.
+ *
+ *     RECVDONE -> SEND if the data for a reply is at hand.
+ *
+ *     SEND -> RECV when a senddone event was received.
+ *
+ *     At any time -> RECV on error.  If RECV fails, the client will
+ *     self-destroy, closing the socket and freeing memory.
+ */
+#define ISC_HTTPD_STATEIDLE    0
+#define ISC_HTTPD_STATERECV    1
+#define ISC_HTTPD_STATERECVDONE        2
+#define ISC_HTTPD_STATESEND    3
+#define ISC_HTTPD_STATESENDDONE        4
+
+#define ISC_HTTPD_ISRECV(c)    ((c)->state == ISC_HTTPD_STATERECV)
+#define ISC_HTTPD_ISRECVDONE(c)        ((c)->state == ISC_HTTPD_STATERECVDONE)
+#define ISC_HTTPD_ISSEND(c)    ((c)->state == ISC_HTTPD_STATESEND)
+#define ISC_HTTPD_ISSENDDONE(c)        ((c)->state == ISC_HTTPD_STATESENDDONE)
+
+/*%
+ * Overall magic test that means we're not idle.
+ */
+#define ISC_HTTPD_SETRECV(c)   ((c)->state = ISC_HTTPD_STATERECV)
+#define ISC_HTTPD_SETRECVDONE(c)       ((c)->state = ISC_HTTPD_STATERECVDONE)
+#define ISC_HTTPD_SETSEND(c)   ((c)->state = ISC_HTTPD_STATESEND)
+#define ISC_HTTPD_SETSENDDONE(c)       ((c)->state = ISC_HTTPD_STATESENDDONE)
+
+static void isc_httpd_accept(isc_task_t *, isc_event_t *);
+static void isc_httpd_recvdone(isc_task_t *, isc_event_t *);
+static void isc_httpd_senddone(isc_task_t *, isc_event_t *);
+static void destroy_client(isc_httpd_t **);
+static isc_result_t process_request(isc_httpd_t *, int);
+static void httpdmgr_destroy(isc_httpdmgr_t *);
+static isc_result_t grow_headerspace(isc_httpd_t *);
+static void reset_client(isc_httpd_t *httpd);
+static isc_result_t render_404(const char *, const char *,
+                              void *,
+                              unsigned int *, const char **,
+                              const char **, isc_buffer_t *,
+                              isc_httpdfree_t **, void **);
+
+static void
+destroy_client(isc_httpd_t **httpdp)
+{
+       isc_httpd_t *httpd = *httpdp;
+       isc_httpdmgr_t *httpdmgr = httpd->mgr;
+
+       *httpdp = NULL;
+
+       LOCK(&httpdmgr->lock);
+
+       isc_socket_detach(&httpd->sock);
+       ISC_LIST_UNLINK(httpdmgr->running, httpd, link);
+
+       if (httpd->headerlen > 0)
+               isc_mem_put(httpdmgr->mctx, httpd->headerdata,
+                           httpd->headerlen);
+
+       isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t));
+
+       UNLOCK(&httpdmgr->lock);
+
+       httpdmgr_destroy(httpdmgr);
+}
+
+isc_result_t
+isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
+                   isc_httpdclientok_t *client_ok,
+                   isc_httpdondestroy_t *ondestroy, void *cb_arg,
+                   isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp)
+{
+       isc_result_t result;
+       isc_httpdmgr_t *httpd;
+
+       REQUIRE(mctx != NULL);
+       REQUIRE(sock != NULL);
+       REQUIRE(task != NULL);
+       REQUIRE(tmgr != NULL);
+       REQUIRE(httpdp != NULL && *httpdp == NULL);
+
+       httpd = isc_mem_get(mctx, sizeof(isc_httpdmgr_t));
+       if (httpd == NULL)
+               return (ISC_R_NOMEMORY);
+
+       result = isc_mutex_init(&httpd->lock);
+       if (result != ISC_R_SUCCESS) {
+               isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t));
+               return (result);
+       }
+       httpd->mctx = NULL;
+       isc_mem_attach(mctx, &httpd->mctx);
+       httpd->sock = NULL;
+       isc_socket_attach(sock, &httpd->sock);
+       httpd->task = NULL;
+       isc_task_attach(task, &httpd->task);
+       httpd->timermgr = tmgr; /* XXXMLG no attach function? */
+       httpd->client_ok = client_ok;
+       httpd->ondestroy = ondestroy;
+       httpd->cb_arg = cb_arg;
+
+       ISC_LIST_INIT(httpd->running);
+       ISC_LIST_INIT(httpd->urls);
+
+       /* XXXMLG ignore errors on isc_socket_listen() */
+       result = isc_socket_listen(sock, SOMAXCONN);
+       if (result != ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_socket_listen() failed: %s",
+                                isc_result_totext(result));
+               goto cleanup;
+       }
+
+       (void)isc_socket_filter(sock, "httpready");
+
+       result = isc_socket_accept(sock, task, isc_httpd_accept, httpd);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
+       httpd->render_404 = render_404;
+
+       *httpdp = httpd;
+       return (ISC_R_SUCCESS);
+
+  cleanup:
+       isc_task_detach(&httpd->task);
+       isc_socket_detach(&httpd->sock);
+       isc_mem_detach(&httpd->mctx);
+       isc_mutex_destroy(&httpd->lock);
+       isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t));
+       return (result);
+}
+
+static void
+httpdmgr_destroy(isc_httpdmgr_t *httpdmgr)
+{
+       isc_mem_t *mctx;
+       isc_httpdurl_t *url;
+
+       ENTER("httpdmgr_destroy");
+
+       LOCK(&httpdmgr->lock);
+
+       if (!MSHUTTINGDOWN(httpdmgr)) {
+               NOTICE("httpdmgr_destroy not shutting down yet");
+               UNLOCK(&httpdmgr->lock);
+               return;
+       }
+
+       /*
+        * If all clients are not shut down, don't do anything yet.
+        */
+       if (!ISC_LIST_EMPTY(httpdmgr->running)) {
+               NOTICE("httpdmgr_destroy clients still active");
+               UNLOCK(&httpdmgr->lock);
+               return;
+       }
+
+       NOTICE("httpdmgr_destroy detaching socket, task, and timermgr");
+
+       isc_socket_detach(&httpdmgr->sock);
+       isc_task_detach(&httpdmgr->task);
+       httpdmgr->timermgr = NULL;
+
+       /*
+        * Clear out the list of all actions we know about.  Just free the
+        * memory.
+        */
+       url = ISC_LIST_HEAD(httpdmgr->urls);
+       while (url != NULL) {
+               isc_mem_free(httpdmgr->mctx, url->url);
+               ISC_LIST_UNLINK(httpdmgr->urls, url, link);
+               isc_mem_put(httpdmgr->mctx, url, sizeof(isc_httpdurl_t));
+               url = ISC_LIST_HEAD(httpdmgr->urls);
+       }
+
+       UNLOCK(&httpdmgr->lock);
+       isc_mutex_destroy(&httpdmgr->lock);
+
+       if (httpdmgr->ondestroy != NULL)
+               (httpdmgr->ondestroy)(httpdmgr->cb_arg);
+
+       mctx = httpdmgr->mctx;
+       isc_mem_putanddetach(&mctx, httpdmgr, sizeof(isc_httpdmgr_t));
+
+       EXIT("httpdmgr_destroy");
+}
+
+#define LENGTHOK(s) (httpd->recvbuf - (s) < (int)httpd->recvlen)
+#define BUFLENOK(s) (httpd->recvbuf - (s) < HTTP_RECVLEN)
+
+static isc_result_t
+process_request(isc_httpd_t *httpd, int length)
+{
+       char *s;
+       char *p;
+       int delim;
+
+       ENTER("request");
+
+       httpd->recvlen += length;
+
+       httpd->recvbuf[httpd->recvlen] = 0;
+
+       /*
+        * If we don't find a blank line in our buffer, return that we need
+        * more data.
+        */
+       s = strstr(httpd->recvbuf, "\r\n\r\n");
+       delim = 1;
+       if (s == NULL) {
+               s = strstr(httpd->recvbuf, "\n\n");
+               delim = 2;
+       }
+       if (s == NULL)
+               return (ISC_R_NOTFOUND);
+
+       /*
+        * Determine if this is a POST or GET method.  Any other values will
+        * cause an error to be returned.
+        */
+       if (strncmp(httpd->recvbuf, "GET ", 4) == 0) {
+               httpd->method = ISC_HTTPD_METHODGET;
+               p = httpd->recvbuf + 4;
+       } else if (strncmp(httpd->recvbuf, "POST ", 5) == 0) {
+               httpd->method = ISC_HTTPD_METHODPOST;
+               p = httpd->recvbuf + 5;
+       } else {
+               return (ISC_R_RANGE);
+       }
+
+       /*
+        * From now on, p is the start of our buffer.
+        */
+
+       /*
+        * Extract the URL.
+        */
+       s = p;
+       while (LENGTHOK(s) && BUFLENOK(s) &&
+              (*s != '\n' && *s != '\r' && *s != '\0' && *s != ' '))
+               s++;
+       if (!LENGTHOK(s))
+               return (ISC_R_NOTFOUND);
+       if (!BUFLENOK(s))
+               return (ISC_R_NOMEMORY);
+       *s = 0;
+
+       /*
+        * Make the URL relative.
+        */
+       if ((strncmp(p, "http:/", 6) == 0)
+           || (strncmp(p, "https:/", 7) == 0)) {
+               /* Skip first / */
+               while (*p != '/' && *p != 0)
+                       p++;
+               if (*p == 0)
+                       return (ISC_R_RANGE);
+               p++;
+               /* Skip second / */
+               while (*p != '/' && *p != 0)
+                       p++;
+               if (*p == 0)
+                       return (ISC_R_RANGE);
+               p++;
+               /* Find third / */
+               while (*p != '/' && *p != 0)
+                       p++;
+               if (*p == 0) {
+                       p--;
+                       *p = '/';
+               }
+       }
+
+       httpd->url = p;
+       p = s + delim;
+       s = p;
+
+       /*
+        * Now, see if there is a ? mark in the URL.  If so, this is
+        * part of the query string, and we will split it from the URL.
+        */
+       httpd->querystring = strchr(httpd->url, '?');
+       if (httpd->querystring != NULL) {
+               *(httpd->querystring) = 0;
+               httpd->querystring++;
+       }
+
+       /*
+        * Extract the HTTP/1.X protocol.  We will bounce on anything but
+        * HTTP/1.1 for now.
+        */
+       while (LENGTHOK(s) && BUFLENOK(s) &&
+              (*s != '\n' && *s != '\r' && *s != '\0'))
+               s++;
+       if (!LENGTHOK(s))
+               return (ISC_R_NOTFOUND);
+       if (!BUFLENOK(s))
+               return (ISC_R_NOMEMORY);
+       *s = 0;
+       if ((strncmp(p, "HTTP/1.0", 8) != 0)
+           && (strncmp(p, "HTTP/1.1", 8) != 0))
+               return (ISC_R_RANGE);
+       httpd->protocol = p;
+       p = s + 1;
+       s = p;
+
+       if (strstr(s, "Connection: close") != NULL)
+               httpd->flags |= HTTPD_CLOSE;
+
+       if (strstr(s, "Host: ") != NULL)
+               httpd->flags |= HTTPD_FOUNDHOST;
+
+       /*
+        * Standards compliance hooks here.
+        */
+       if (strcmp(httpd->protocol, "HTTP/1.1") == 0
+           && ((httpd->flags & HTTPD_FOUNDHOST) == 0))
+               return (ISC_R_RANGE);
+
+       EXIT("request");
+
+       return (ISC_R_SUCCESS);
+}
+
+static void
+isc_httpd_accept(isc_task_t *task, isc_event_t *ev)
+{
+       isc_result_t result;
+       isc_httpdmgr_t *httpdmgr = ev->ev_arg;
+       isc_httpd_t *httpd;
+       isc_region_t r;
+       isc_socket_newconnev_t *nev = (isc_socket_newconnev_t *)ev;
+       isc_sockaddr_t peeraddr;
+
+       ENTER("accept");
+
+       LOCK(&httpdmgr->lock);
+       if (MSHUTTINGDOWN(httpdmgr)) {
+               NOTICE("accept shutting down, goto out");
+               goto out;
+       }
+
+       if (nev->result == ISC_R_CANCELED) {
+               NOTICE("accept canceled, goto out");
+               goto out;
+       }
+
+       if (nev->result != ISC_R_SUCCESS) {
+               /* XXXMLG log failure */
+               NOTICE("accept returned failure, goto requeue");
+               goto requeue;
+       }
+
+       (void)isc_socket_getpeername(nev->newsocket, &peeraddr);
+       if (httpdmgr->client_ok != NULL &&
+           !(httpdmgr->client_ok)(&peeraddr, httpdmgr->cb_arg)) {
+               isc_socket_detach(&nev->newsocket);
+               goto requeue;
+       }
+
+       httpd = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpd_t));
+       if (httpd == NULL) {
+               /* XXXMLG log failure */
+               NOTICE("accept failed to allocate memory, goto requeue");
+               isc_socket_detach(&nev->newsocket);
+               goto requeue;
+       }
+
+       httpd->mgr = httpdmgr;
+       ISC_LINK_INIT(httpd, link);
+       ISC_LIST_APPEND(httpdmgr->running, httpd, link);
+       ISC_HTTPD_SETRECV(httpd);
+       httpd->sock = nev->newsocket;
+       isc_socket_setname(httpd->sock, "httpd", NULL);
+       httpd->flags = 0;
+
+       /*
+        * Initialize the buffer for our headers.
+        */
+       httpd->headerdata = isc_mem_get(httpdmgr->mctx, HTTP_SENDGROW);
+       if (httpd->headerdata == NULL) {
+               isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t));
+               isc_socket_detach(&nev->newsocket);
+               goto requeue;
+       }
+       httpd->headerlen = HTTP_SENDGROW;
+       isc_buffer_init(&httpd->headerbuffer, httpd->headerdata,
+                       httpd->headerlen);
+
+       ISC_LIST_INIT(httpd->bufflist);
+
+       isc_buffer_initnull(&httpd->bodybuffer);
+       reset_client(httpd);
+
+       r.base = (unsigned char *)httpd->recvbuf;
+       r.length = HTTP_RECVLEN - 1;
+       result = isc_socket_recv(httpd->sock, &r, 1, task, isc_httpd_recvdone,
+                                httpd);
+       NOTICE("accept queued recv on socket");
+
+ requeue:
+       result = isc_socket_accept(httpdmgr->sock, task, isc_httpd_accept,
+                                  httpdmgr);
+       if (result != ISC_R_SUCCESS) {
+               /* XXXMLG what to do?  Log failure... */
+               NOTICE("accept could not reaccept due to failure");
+       }
+
+ out:
+       UNLOCK(&httpdmgr->lock);
+
+       httpdmgr_destroy(httpdmgr);
+
+       isc_event_free(&ev);
+
+       EXIT("accept");
+}
+
+static isc_result_t
+render_404(const char *url, const char *querystring,
+          void *arg,
+          unsigned int *retcode, const char **retmsg,
+          const char **mimetype, isc_buffer_t *b,
+          isc_httpdfree_t **freecb, void **freecb_args)
+{
+       static char msg[] = "No such URL.";
+
+       UNUSED(url);
+       UNUSED(querystring);
+       UNUSED(arg);
+
+       *retcode = 404;
+       *retmsg = "No such URL";
+       *mimetype = "text/plain";
+       isc_buffer_reinit(b, msg, strlen(msg));
+       isc_buffer_add(b, strlen(msg));
+       *freecb = NULL;
+       *freecb_args = NULL;
+
+       return (ISC_R_SUCCESS);
+}
+
+static void
+isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev)
+{
+       isc_region_t r;
+       isc_result_t result;
+       isc_httpd_t *httpd = ev->ev_arg;
+       isc_socketevent_t *sev = (isc_socketevent_t *)ev;
+       isc_httpdurl_t *url;
+       isc_time_t now;
+       char datebuf[32];  /* Only need 30, but safety first */
+
+       ENTER("recv");
+
+       INSIST(ISC_HTTPD_ISRECV(httpd));
+
+       if (sev->result != ISC_R_SUCCESS) {
+               NOTICE("recv destroying client");
+               destroy_client(&httpd);
+               goto out;
+       }
+
+       result = process_request(httpd, sev->n);
+       if (result == ISC_R_NOTFOUND) {
+               if (httpd->recvlen >= HTTP_RECVLEN - 1) {
+                       destroy_client(&httpd);
+                       goto out;
+               }
+               r.base = (unsigned char *)httpd->recvbuf + httpd->recvlen;
+               r.length = HTTP_RECVLEN - httpd->recvlen - 1;
+               result = isc_socket_recv(httpd->sock, &r, 1, task,
+                                        isc_httpd_recvdone, httpd);
+               goto out;
+       } else if (result != ISC_R_SUCCESS) {
+               destroy_client(&httpd);
+               goto out;
+       }
+
+       ISC_HTTPD_SETSEND(httpd);
+
+       /*
+        * XXXMLG Call function here.  Provide an add-header function
+        * which will append the common headers to a response we generate.
+        */
+       isc_buffer_initnull(&httpd->bodybuffer);
+       isc_time_now(&now);
+       isc_time_formathttptimestamp(&now, datebuf, sizeof(datebuf));
+       url = ISC_LIST_HEAD(httpd->mgr->urls);
+       while (url != NULL) {
+               if (strcmp(httpd->url, url->url) == 0)
+                       break;
+               url = ISC_LIST_NEXT(url, link);
+       }
+       if (url == NULL)
+               result = httpd->mgr->render_404(httpd->url, httpd->querystring,
+                                               NULL,
+                                               &httpd->retcode,
+                                               &httpd->retmsg,
+                                               &httpd->mimetype,
+                                               &httpd->bodybuffer,
+                                               &httpd->freecb,
+                                               &httpd->freecb_arg);
+       else
+               result = url->action(httpd->url, httpd->querystring,
+                                    url->action_arg,
+                                    &httpd->retcode, &httpd->retmsg,
+                                    &httpd->mimetype, &httpd->bodybuffer,
+                                    &httpd->freecb, &httpd->freecb_arg);
+       if (result != ISC_R_SUCCESS) {
+               destroy_client(&httpd);
+               goto out;
+       }
+
+       isc_httpd_response(httpd);
+       isc_httpd_addheader(httpd, "Content-Type", httpd->mimetype);
+       isc_httpd_addheader(httpd, "Date", datebuf);
+       isc_httpd_addheader(httpd, "Expires", datebuf);
+       isc_httpd_addheader(httpd, "Last-Modified", datebuf);
+       isc_httpd_addheader(httpd, "Pragma: no-cache", NULL);
+       isc_httpd_addheader(httpd, "Cache-Control: no-cache", NULL);
+       isc_httpd_addheader(httpd, "Server: libisc", NULL);
+       isc_httpd_addheaderuint(httpd, "Content-Length",
+                               isc_buffer_usedlength(&httpd->bodybuffer));
+       isc_httpd_endheaders(httpd);  /* done */
+
+       ISC_LIST_APPEND(httpd->bufflist, &httpd->headerbuffer, link);
+       /*
+        * Link the data buffer into our send queue, should we have any data
+        * rendered into it.  If no data is present, we won't do anything
+        * with the buffer.
+        */
+       if (isc_buffer_length(&httpd->bodybuffer) > 0)
+               ISC_LIST_APPEND(httpd->bufflist, &httpd->bodybuffer, link);
+
+       result = isc_socket_sendv(httpd->sock, &httpd->bufflist, task,
+                                 isc_httpd_senddone, httpd);
+
+ out:
+       isc_event_free(&ev);
+       EXIT("recv");
+}
+
+void
+isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp)
+{
+       isc_httpdmgr_t *httpdmgr;
+       isc_httpd_t *httpd;
+       httpdmgr = *httpdmgrp;
+       *httpdmgrp = NULL;
+
+       ENTER("isc_httpdmgr_shutdown");
+
+       LOCK(&httpdmgr->lock);
+
+       MSETSHUTTINGDOWN(httpdmgr);
+
+       isc_socket_cancel(httpdmgr->sock, httpdmgr->task, ISC_SOCKCANCEL_ALL);
+
+       httpd = ISC_LIST_HEAD(httpdmgr->running);
+       while (httpd != NULL) {
+               isc_socket_cancel(httpd->sock, httpdmgr->task,
+                                 ISC_SOCKCANCEL_ALL);
+               httpd = ISC_LIST_NEXT(httpd, link);
+       }
+
+       UNLOCK(&httpdmgr->lock);
+
+       EXIT("isc_httpdmgr_shutdown");
+}
+
+static isc_result_t
+grow_headerspace(isc_httpd_t *httpd)
+{
+       char *newspace;
+       unsigned int newlen;
+       isc_region_t r;
+
+       newlen = httpd->headerlen + HTTP_SENDGROW;
+       if (newlen > HTTP_SEND_MAXLEN)
+               return (ISC_R_NOSPACE);
+
+       newspace = isc_mem_get(httpd->mgr->mctx, newlen);
+       if (newspace == NULL)
+               return (ISC_R_NOMEMORY);
+       isc_buffer_region(&httpd->headerbuffer, &r);
+       isc_buffer_reinit(&httpd->headerbuffer, newspace, newlen);
+
+       isc_mem_put(httpd->mgr->mctx, r.base, r.length);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_httpd_response(isc_httpd_t *httpd)
+{
+       isc_result_t result;
+       unsigned int needlen;
+
+       needlen = strlen(httpd->protocol) + 1; /* protocol + space */
+       needlen += 3 + 1;  /* room for response code, always 3 bytes */
+       needlen += strlen(httpd->retmsg) + 2;  /* return msg + CRLF */
+
+       if (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
+               result = grow_headerspace(httpd);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+       }
+
+       sprintf(isc_buffer_used(&httpd->headerbuffer), "%s %03d %s\r\n",
+               httpd->protocol, httpd->retcode, httpd->retmsg);
+       isc_buffer_add(&httpd->headerbuffer, needlen);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_httpd_addheader(isc_httpd_t *httpd, const char *name,
+                   const char *val)
+{
+       isc_result_t result;
+       unsigned int needlen;
+
+       needlen = strlen(name); /* name itself */
+       if (val != NULL)
+               needlen += 2 + strlen(val); /* :<space> and val */
+       needlen += 2; /* CRLF */
+
+       if (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
+               result = grow_headerspace(httpd);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+       }
+
+       if (val != NULL)
+               sprintf(isc_buffer_used(&httpd->headerbuffer),
+                       "%s: %s\r\n", name, val);
+       else
+               sprintf(isc_buffer_used(&httpd->headerbuffer),
+                       "%s\r\n", name);
+
+       isc_buffer_add(&httpd->headerbuffer, needlen);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_httpd_endheaders(isc_httpd_t *httpd)
+{
+       isc_result_t result;
+
+       if (isc_buffer_availablelength(&httpd->headerbuffer) < 2) {
+               result = grow_headerspace(httpd);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+       }
+
+       sprintf(isc_buffer_used(&httpd->headerbuffer), "\r\n");
+       isc_buffer_add(&httpd->headerbuffer, 2);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) {
+       isc_result_t result;
+       unsigned int needlen;
+       char buf[sizeof "18446744073709551616"];
+
+       sprintf(buf, "%d", val);
+
+       needlen = strlen(name); /* name itself */
+       needlen += 2 + strlen(buf); /* :<space> and val */
+       needlen += 2; /* CRLF */
+
+       if (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
+               result = grow_headerspace(httpd);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+       }
+
+       sprintf(isc_buffer_used(&httpd->headerbuffer),
+               "%s: %s\r\n", name, buf);
+
+       isc_buffer_add(&httpd->headerbuffer, needlen);
+
+       return (ISC_R_SUCCESS);
+}
+
+static void
+isc_httpd_senddone(isc_task_t *task, isc_event_t *ev)
+{
+       isc_httpd_t *httpd = ev->ev_arg;
+       isc_region_t r;
+       isc_result_t result;
+       isc_socketevent_t *sev = (isc_socketevent_t *)ev;
+
+       ENTER("senddone");
+       INSIST(ISC_HTTPD_ISSEND(httpd));
+
+       /*
+        * First, unlink our header buffer from the socket's bufflist.  This
+        * is sort of an evil hack, since we know our buffer will be there,
+        * and we know it's address, so we can just remove it directly.
+        */
+       NOTICE("senddone unlinked header");
+       ISC_LIST_UNLINK(sev->bufferlist, &httpd->headerbuffer, link);
+
+       /*
+        * We will always want to clean up our receive buffer, even if we
+        * got an error on send or we are shutting down.
+        *
+        * We will pass in the buffer only if there is data in it.  If
+        * there is no data, we will pass in a NULL.
+        */
+       if (httpd->freecb != NULL) {
+               isc_buffer_t *b = NULL;
+               if (isc_buffer_length(&httpd->bodybuffer) > 0)
+                       b = &httpd->bodybuffer;
+               httpd->freecb(b, httpd->freecb_arg);
+               NOTICE("senddone free callback performed");
+       }
+       if (ISC_LINK_LINKED(&httpd->bodybuffer, link)) {
+               ISC_LIST_UNLINK(sev->bufferlist, &httpd->bodybuffer, link);
+               NOTICE("senddone body buffer unlinked");
+       }
+
+       if (sev->result != ISC_R_SUCCESS) {
+               destroy_client(&httpd);
+               goto out;
+       }
+
+       if ((httpd->flags & HTTPD_CLOSE) != 0) {
+               destroy_client(&httpd);
+               goto out;
+       }
+
+       ISC_HTTPD_SETRECV(httpd);
+
+       NOTICE("senddone restarting recv on socket");
+
+       reset_client(httpd);
+
+       r.base = (unsigned char *)httpd->recvbuf;
+       r.length = HTTP_RECVLEN - 1;
+       result = isc_socket_recv(httpd->sock, &r, 1, task, isc_httpd_recvdone,
+                                httpd);
+
+out:
+       isc_event_free(&ev);
+       EXIT("senddone");
+}
+
+static void
+reset_client(isc_httpd_t *httpd)
+{
+       /*
+        * Catch errors here.  We MUST be in RECV mode, and we MUST NOT have
+        * any outstanding buffers.  If we have buffers, we have a leak.
+        */
+       INSIST(ISC_HTTPD_ISRECV(httpd));
+       INSIST(!ISC_LINK_LINKED(&httpd->headerbuffer, link));
+       INSIST(!ISC_LINK_LINKED(&httpd->bodybuffer, link));
+
+       httpd->recvbuf[0] = 0;
+       httpd->recvlen = 0;
+       httpd->method = ISC_HTTPD_METHODUNKNOWN;
+       httpd->url = NULL;
+       httpd->querystring = NULL;
+       httpd->protocol = NULL;
+       httpd->flags = 0;
+
+       isc_buffer_clear(&httpd->headerbuffer);
+       isc_buffer_invalidate(&httpd->bodybuffer);
+}
+
+isc_result_t
+isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url,
+                   isc_httpdaction_t *func, void *arg)
+{
+       isc_httpdurl_t *item;
+
+       if (url == NULL) {
+               httpdmgr->render_404 = func;
+               return (ISC_R_SUCCESS);
+       }
+
+       item = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpdurl_t));
+       if (item == NULL)
+               return (ISC_R_NOMEMORY);
+
+       item->url = isc_mem_strdup(httpdmgr->mctx, url);
+       if (item->url == NULL) {
+               isc_mem_put(httpdmgr->mctx, item, sizeof(isc_httpdurl_t));
+               return (ISC_R_NOMEMORY);
+       }
+
+       item->action = func;
+       item->action_arg = arg;
+       ISC_LINK_INIT(item, link);
+       ISC_LIST_APPEND(httpdmgr->urls, item, link);
+
+       return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/ia64/include/isc/atomic.h b/lib/isc/ia64/include/isc/atomic.h
new file mode 100644 (file)
index 0000000..4c46797
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2006, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.4.326.2 2009/02/06 23:47:11 tbox Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ *
+ * Open issue: can 'fetchadd' make the code faster for some particular values
+ * (e.g., 1 and -1)?
+ */
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val)
+#ifdef __GNUC__
+__attribute__ ((unused))
+#endif
+{
+       isc_int32_t prev, swapped;
+
+       for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) {
+               swapped = prev + val;
+               __asm__ volatile(
+                       "mov ar.ccv=%2;"
+                       "cmpxchg4.acq %0=%4,%3,ar.ccv"
+                       : "=r" (swapped), "=m" (*p)
+                       : "r" (prev), "r" (swapped), "m" (*p)
+                       : "memory");
+               if (swapped == prev)
+                       break;
+       }
+
+       return (prev);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val)
+#ifdef __GNUC__
+__attribute__ ((unused))
+#endif
+{
+       __asm__ volatile(
+               "st4.rel %0=%1"
+               : "=m" (*p)
+               : "r" (val)
+               : "memory"
+               );
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'.  The original value is returned in any
+ * case.
+ */
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val)
+#ifdef __GNUC__
+__attribute__ ((unused))
+#endif
+{
+       isc_int32_t ret;
+
+       __asm__ volatile(
+               "mov ar.ccv=%2;"
+               "cmpxchg4.acq %0=%4,%3,ar.ccv"
+               : "=r" (ret), "=m" (*p)
+               : "r" (cmpval), "r" (val), "m" (*p)
+               : "memory");
+
+       return (ret);
+}
+#else /* !ISC_PLATFORM_USEGCCASM */
+
+#error "unsupported compiler.  disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
index 5aa3d23acacaeb60c0a4822bb633c9ee3dc243a1..c4d54cbe44d9a6d203cdb7d17229c713799380c9 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: app.h,v 1.1 2001/07/06 19:50:03 gson Exp $ */
+/* $Id: app.h,v 1.8 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_APP_H
 #define ISC_APP_H 1
  ***** Module Info
  *****/
 
-/*
- * ISC Application Support
+/*! \file isc/app.h
+ * \brief ISC Application Support
  *
  * Dealing with program termination can be difficult, especially in a
  * multithreaded program.  The routines in this module help coordinate
  * the shutdown process.  They are used as follows by the initial (main)
  * thread of the application:
  *
- *             isc_app_start();        Call very early in main(), before
+ *\li          isc_app_start();        Call very early in main(), before
  *                                     any other threads have been created.
  *
- *             isc_app_run();          This will post any on-run events,
+ *\li          isc_app_run();          This will post any on-run events,
  *                                     and then block until application
  *                                     shutdown is requested.  A shutdown
  *                                     request is made by calling
@@ -44,7 +44,7 @@
  *                                     After isc_app_run() returns, the
  *                                     application should shutdown itself.
  *
- *             isc_app_finish();       Call very late in main().
+ *\li          isc_app_finish();       Call very late in main().
  *
  * Applications that want to use SIGHUP/isc_app_reload() to trigger reloading
  * should check the result of isc_app_run() and call the reload routine if
  * Use of this module is not required.  In particular, isc_app_start() is
  * NOT an ISC library initialization routine.
  *
- * MP:
+ * \li MP:
  *     Clients must ensure that isc_app_start(), isc_app_run(), and
  *     isc_app_finish() are called at most once.  isc_app_shutdown()
  *     is safe to use by any thread (provided isc_app_start() has been
  *     called previously).
  *
- * Reliability:
+ * \li Reliability:
  *     No anticipated impact.
  *
- * Resources:
+ * \li Resources:
  *     None.
  *
- * Security:
+ * \li Security:
  *     No anticipated impact.
  *
- * Standards:
+ * \li Standards:
  *     None.
  */
 
@@ -87,8 +87,8 @@ ISC_LANG_BEGINDECLS
 
 isc_result_t
 isc_app_start(void);
-/*
- * Start an ISC library application.
+/*!<
+ * \brief Start an ISC library application.
  *
  * Notes:
  *     This call should be made before any other ISC library call, and as
@@ -98,8 +98,8 @@ isc_app_start(void);
 isc_result_t
 isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
              void *arg);
-/*
- * Request delivery of an event when the application is run.
+/*!<
+ * \brief Request delivery of an event when the application is run.
  *
  * Requires:
  *     isc_app_start() has been called.
@@ -111,99 +111,99 @@ isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
 
 isc_result_t
 isc_app_run(void);
-/*
- * Run an ISC library application.
+/*!<
+ * \brief Run an ISC library application.
  *
  * Notes:
- *     The caller (typically the initial thread of an application) will
+ *\li  The caller (typically the initial thread of an application) will
  *     block until shutdown is requested.  When the call returns, the
  *     caller should start shutting down the application.
  *
  * Requires:
- *     isc_app_start() has been called.
+ *\li  isc_app_start() has been called.
  *
  * Ensures:
- *     Any events requested via isc_app_onrun() will have been posted (in
+ *\li  Any events requested via isc_app_onrun() will have been posted (in
  *     FIFO order) before isc_app_run() blocks.
  *
  * Returns:
- *     ISC_R_SUCCESS                   Shutdown has been requested.
- *     ISC_R_RELOAD                    Reload has been requested.
+ *\li  ISC_R_SUCCESS                   Shutdown has been requested.
+ *\li  ISC_R_RELOAD                    Reload has been requested.
  */
 
 isc_result_t
 isc_app_shutdown(void);
-/*
- * Request application shutdown.
+/*!<
+ * \brief Request application shutdown.
  *
  * Notes:
- *     It is safe to call isc_app_shutdown() multiple times.  Shutdown will
+ *\li  It is safe to call isc_app_shutdown() multiple times.  Shutdown will
  *     only be triggered once.
  *
  * Requires:
- *     isc_app_run() has been called.
+ *\li  isc_app_run() has been called.
  *
  * Returns:
- *     ISC_R_SUCCESS
- *     ISC_R_UNEXPECTED
+ *\li  ISC_R_SUCCESS
+ *\li  ISC_R_UNEXPECTED
  */
 
 isc_result_t
 isc_app_reload(void);
-/*
- * Request application reload.
+/*!<
+ * \brief Request application reload.
  *
  * Requires:
- *     isc_app_run() has been called.
+ *\li  isc_app_run() has been called.
  *
  * Returns:
- *     ISC_R_SUCCESS
- *     ISC_R_UNEXPECTED
+ *\li  ISC_R_SUCCESS
+ *\li  ISC_R_UNEXPECTED
  */
 
 void
 isc_app_finish(void);
-/*
- * Finish an ISC library application.
+/*!<
+ * \brief Finish an ISC library application.
  *
  * Notes:
- *     This call should be made at or near the end of main().
+ *\li  This call should be made at or near the end of main().
  *
  * Requires:
- *     isc_app_start() has been called.
+ *\li  isc_app_start() has been called.
  *
  * Ensures:
- *     Any resources allocated by isc_app_start() have been released.
+ *\li  Any resources allocated by isc_app_start() have been released.
  */
 
 void
 isc_app_block(void);
-/*
- * Indicate that a blocking operation will be performed.
+/*!<
+ * \brief Indicate that a blocking operation will be performed.
  *
  * Notes:
- *     If a blocking operation is in process, a call to isc_app_shutdown()
+ *\li  If a blocking operation is in process, a call to isc_app_shutdown()
  *     or an external signal will abort the program, rather than allowing
  *     clean shutdown.  This is primarily useful for reading user input.
  *
  * Requires:
- *     isc_app_start() has been called.
- *     No other blocking operations are in progress.
+ * \li isc_app_start() has been called.
+ * \li No other blocking operations are in progress.
  */
 
 void
 isc_app_unblock(void);
-/*
- * Indicate that a blocking operation is complete.
+/*!<
+ * \brief Indicate that a blocking operation is complete.
  *
  * Notes:
- *     When a blocking operation has completed, return the program to a
+ * \li When a blocking operation has completed, return the program to a
  *     state where a call to isc_app_shutdown() or an external signal will
  *     shutdown normally.
  *
  * Requires:
- *     isc_app_start() has been called.
- *     isc_app_block() has been called by the same thread.
+ * \li isc_app_start() has been called.
+ * \li isc_app_block() has been called by the same thread.
  */
 
 
index 45855c663180edf31ed15b31fde4886f02e8cc1e..b03115216909b8f9d8bcfed5b3327173ad91fa22 100644 (file)
@@ -1,22 +1,24 @@
 /*
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1997-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
 /*
- * $Id: assertions.h,v 1.17 2001/07/12 05:58:21 mayer Exp $
+ * $Id: assertions.h,v 1.26 2008/10/15 23:47:31 tbox Exp $
+ */
+/*! \file isc/assertions.h
  */
 
 #ifndef ISC_ASSERTIONS_H
@@ -27,6 +29,7 @@
 
 ISC_LANG_BEGINDECLS
 
+/*% isc assertion type */
 typedef enum {
        isc_assertiontype_require,
        isc_assertiontype_ensure,
@@ -37,6 +40,7 @@ typedef enum {
 typedef void (*isc_assertioncallback_t)(const char *, int, isc_assertiontype_t,
                                        const char *);
 
+/* coverity[+kill] */
 LIBISC_EXTERNAL_DATA extern isc_assertioncallback_t isc_assertion_failed;
 
 void
@@ -45,14 +49,14 @@ isc_assertion_setcallback(isc_assertioncallback_t);
 const char *
 isc_assertion_typetotext(isc_assertiontype_t type);
 
-#ifdef ISC_CHECK_ALL
+#if defined(ISC_CHECK_ALL) || defined(__COVERITY__)
 #define ISC_CHECK_REQUIRE              1
 #define ISC_CHECK_ENSURE               1
 #define ISC_CHECK_INSIST               1
 #define ISC_CHECK_INVARIANT            1
 #endif
 
-#ifdef ISC_CHECK_NONE
+#if defined(ISC_CHECK_NONE) && !defined(__COVERITY__)
 #define ISC_CHECK_REQUIRE              0
 #define ISC_CHECK_ENSURE               0
 #define ISC_CHECK_INSIST               0
diff --git a/lib/isc/include/isc/base32.h b/lib/isc/include/isc/base32.h
new file mode 100644 (file)
index 0000000..978a8db
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: base32.h,v 1.3 2008/09/25 04:02:39 tbox Exp $ */
+
+#ifndef ISC_BASE32_H
+#define ISC_BASE32_H 1
+
+/*! \file */
+
+/*
+ * Routines for manipulating base 32 and base 32 hex encoded data.
+ * Based on RFC 4648.
+ *
+ * Base 32 hex preserves the sort order of data when it is encoded /
+ * decoded.
+ */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_base32_totext(isc_region_t *source, int wordlength,
+                 const char *wordbreak, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_totext(isc_region_t *source, int wordlength,
+                    const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into base32 encoded text.
+ *
+ * Notes:
+ *\li  The base32 encoded text in 'target' will be divided into
+ *     words of at most 'wordlength' characters, separated by
+ *     the 'wordbreak' string.  No parentheses will surround
+ *     the text.
+ *
+ * Requires:
+ *\li  'source' is a region containing binary data
+ *\li  'target' is a text buffer containing available space
+ *\li  'wordbreak' points to a null-terminated string of
+ *             zero or more whitespace characters
+ *
+ * Ensures:
+ *\li  target will contain the base32 encoded version of the data
+ *     in source.  The 'used' pointer in target will be advanced as
+ *     necessary.
+ */
+
+isc_result_t
+isc_base32_decodestring(const char *cstr, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated base32 string.
+ *
+ * Requires:
+ *\li  'cstr' is non-null.
+ *\li  'target' is a valid buffer.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS  -- the entire decoded representation of 'cstring'
+ *                        fit in 'target'.
+ *\li  #ISC_R_BADBASE32 -- 'cstr' is not a valid base32 encoding.
+ *
+ *     Other error returns are any possible error code from:
+ *\li          isc_lex_create(),
+ *\li          isc_lex_openbuffer(),
+ *\li          isc_base32_tobuffer().
+ */
+
+isc_result_t
+isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+isc_result_t
+isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert base32 encoded text from a lexer context into data.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer context
+ *\li  'target' is a buffer containing binary data
+ *\li  'length' is an integer
+ *
+ * Ensures:
+ *\li  target will contain the data represented by the base32 encoded
+ *     string parsed by the lexer.  No more than length bytes will be read,
+ *     if length is positive.  The 'used' pointer in target will be
+ *     advanced as necessary.
+ */
+
+isc_result_t
+isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target);
+/*!<
+ * \brief Decode a packed (no white space permitted) base32 region.
+ *
+ * Requires:
+ *\li   'source' is a valid region.
+ *\li   'target' is a valid buffer.
+ *
+ * Returns:
+ *\li   #ISC_R_SUCCESS  -- the entire decoded representation of 'cstring'
+ *                         fit in 'target'.
+ *\li   #ISC_R_BADBASE32 -- 'source' is not a valid base32 encoding.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BASE32_H */
diff --git a/lib/isc/include/isc/base64.h b/lib/isc/include/isc/base64.h
new file mode 100644 (file)
index 0000000..e48ef2a
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: base64.h,v 1.22 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_BASE64_H
+#define ISC_BASE64_H 1
+
+/*! \file isc/base64.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_base64_totext(isc_region_t *source, int wordlength,
+                 const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into base64 encoded text.
+ *
+ * Notes:
+ *\li  The base64 encoded text in 'target' will be divided into
+ *     words of at most 'wordlength' characters, separated by
+ *     the 'wordbreak' string.  No parentheses will surround
+ *     the text.
+ *
+ * Requires:
+ *\li  'source' is a region containing binary data
+ *\li  'target' is a text buffer containing available space
+ *\li  'wordbreak' points to a null-terminated string of
+ *             zero or more whitespace characters
+ *
+ * Ensures:
+ *\li  target will contain the base64 encoded version of the data
+ *     in source.  The 'used' pointer in target will be advanced as
+ *     necessary.
+ */
+
+isc_result_t
+isc_base64_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated base64 string.
+ *
+ * Requires:
+ *\li  'cstr' is non-null.
+ *\li  'target' is a valid buffer.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS  -- the entire decoded representation of 'cstring'
+ *                        fit in 'target'.
+ *\li  #ISC_R_BADBASE64 -- 'cstr' is not a valid base64 encoding.
+ *
+ *     Other error returns are any possible error code from:
+ *\li          isc_lex_create(),
+ *\li          isc_lex_openbuffer(),
+ *\li          isc_base64_tobuffer().
+ */
+
+isc_result_t
+isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert base64 encoded text from a lexer context into data.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer context
+ *\li  'target' is a buffer containing binary data
+ *\li  'length' is an integer
+ *
+ * Ensures:
+ *\li  target will contain the data represented by the base64 encoded
+ *     string parsed by the lexer.  No more than length bytes will be read,
+ *     if length is positive.  The 'used' pointer in target will be
+ *     advanced as necessary.
+ */
+
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BASE64_H */
diff --git a/lib/isc/include/isc/bitstring.h b/lib/isc/include/isc/bitstring.h
new file mode 100644 (file)
index 0000000..252d111
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: bitstring.h,v 1.14 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_BITSTRING_H
+#define ISC_BITSTRING_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/bitstring.h
+ *
+ * \brief Bitstring manipulation functions.
+ *
+ * A bitstring is a packed array of bits, stored in a contiguous
+ * sequence of octets.  The "most significant bit" (msb) of a bitstring
+ * is the high bit of the first octet.  The "least significant bit" of a
+ * bitstring is the low bit of the last octet.
+ *
+ * Two bit numbering schemes are supported, "msb0" and "lsb0".
+ *
+ * In the "msb0" scheme, bit number 0 designates the most significant bit,
+ * and any padding bits required to make the bitstring a multiple of 8 bits
+ * long are added to the least significant end of the last octet.
+ *
+ * In the "lsb0" scheme, bit number 0 designates the least significant bit,
+ * and any padding bits required to make the bitstring a multiple of 8 bits
+ * long are added to the most significant end of the first octet.
+ *
+ * E.g., consider the bitstring "11010001111".  This bitstring is 11 bits
+ * long and will take two octets.  Let "p" denote a pad bit.  In the msb0
+ * encoding, it would be
+ *
+ * \verbatim
+ *             Octet 0           Octet 1
+ *                         |
+ *         1 1 0 1 0 0 0 1 | 1 1 1 p p p p p
+ *         ^               |               ^
+ *         |                               |
+ *         bit 0                           bit 15
+ * \endverbatim
+ *
+ * In the lsb0 encoding, it would be
+ *
+ * \verbatim
+ *             Octet 0           Octet 1
+ *                         |
+ *         p p p p p 1 1 0 | 1 0 0 0 1 1 1 1 
+ *         ^               |               ^
+ *         |                               |
+ *         bit 15                          bit 0
+ * \endverbatim
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+struct isc_bitstring {
+       unsigned int            magic;
+       unsigned char *         data;
+       unsigned int            length;
+       unsigned int            size;
+       isc_boolean_t           lsb0;
+};
+
+/***
+ *** Functions
+ ***/
+
+void
+isc_bitstring_init(isc_bitstring_t *bitstring, unsigned char *data,
+                  unsigned int length, unsigned int size, isc_boolean_t lsb0);
+/*!<
+ * \brief Make 'bitstring' refer to the bitstring of 'size' bits starting
+ * at 'data'.  'length' bits of the bitstring are valid.  If 'lsb0'
+ * is set then, bit 0 refers to the least significant bit of the
+ * bitstring.  Otherwise bit 0 is the most significant bit.
+ *
+ * Requires:
+ *
+ *\li  'bitstring' points to a isc_bitstring_t.
+ *
+ *\li  'data' points to an array of unsigned char large enough to hold
+ *     'size' bits.
+ *
+ *\li  'length' <= 'size'.
+ *
+ * Ensures:
+ *
+ *\li  'bitstring' is a valid bitstring.
+ */
+
+void
+isc_bitstring_invalidate(isc_bitstring_t *bitstring);
+/*!<
+ * \brief Invalidate 'bitstring'.
+ *
+ * Requires:
+ *
+ *\li  'bitstring' is a valid bitstring.
+ *
+ * Ensures:
+ *
+ *\li  'bitstring' is not a valid bitstring.
+ */
+
+void
+isc_bitstring_copy(isc_bitstring_t *source, unsigned int sbitpos,
+                  isc_bitstring_t *target, unsigned int tbitpos,
+                  unsigned int n);
+/*!<
+ * \brief Starting at bit 'sbitpos', copy 'n' bits from 'source' to
+ * the 'n' bits of 'target' starting at 'tbitpos'.
+ *
+ * Requires:
+ *
+ *\li  'source' and target are valid bitstrings with the same lsb0 setting.
+ *
+ *\li  'sbitpos' + 'n' is less than or equal to the length of 'source'.
+ *
+ *\li  'tbitpos' + 'n' is less than or equal to the size of 'target'.
+ *
+ * Ensures:
+ *
+ *\li  The specified bits have been copied, and the length of 'target'
+ *     adjusted (if required).
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BITSTRING_H */
index d10007b5802a113f3b8a6d9e0ef5959b713ffb41..348b096912aac81e510e27ac0b0655b3f3e1ec40 100644 (file)
@@ -1,25 +1,27 @@
 /*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: boolean.h,v 1.12 2001/01/09 21:56:45 bwelling Exp $ */
+/* $Id: boolean.h,v 1.19 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_BOOLEAN_H
 #define ISC_BOOLEAN_H 1
 
+/*! \file isc/boolean.h */
+
 typedef enum { isc_boolean_false = 0, isc_boolean_true = 1 } isc_boolean_t;
 
 #define ISC_FALSE isc_boolean_false
index 47c8f0c95d4181bfe63955ad684df282dab21beb..2a02d88e4e8e7e263b29f4ad9d45f2f12e3f8ff1 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: buffer.h,v 1.39.12.2 2004/03/08 09:04:51 marka Exp $ */
+/* $Id: buffer.h,v 1.53 2008/09/25 04:02:39 tbox Exp $ */
 
 #ifndef ISC_BUFFER_H
 #define ISC_BUFFER_H 1
  ***** Module Info
  *****/
 
-/*
- * Buffers
+/*! \file isc/buffer.h
  *
- * A buffer is a region of memory, together with a set of related subregions.
+ * \brief A buffer is a region of memory, together with a set of related subregions.
  * Buffers are used for parsing and I/O operations.
  *
  * The 'used region' and the 'available' region are disjoint, and their
@@ -51,6 +50,7 @@
  * is empty.  If the current offset advances beyond the chosen offset, the
  * active region will also be empty.
  *
+ * \verbatim
  *  /------------entire length---------------\
  *  /----- used region -----\/-- available --\
  *  +----------------------------------------+
  * a-b == consumed region.
  * b-d == remaining region.
  * b-c == optional active region.
+ *\endverbatim
  *
  * The following invariants are maintained by all routines:
  *
+ *\code
  *     length > 0
  *
  *     base is a valid pointer to length bytes of memory
  *
  *     0 <= active <= used
  *     (although active < current implies empty active region)
+ *\endcode
  *
- * MP:
+ * \li MP:
  *     Buffers have no synchronization.  Clients must ensure exclusive
  *     access.
  *
- * Reliability:
+ * \li Reliability:
  *     No anticipated impact.
  *
- * Resources:
+ * \li Resources:
  *     Memory: 1 pointer + 6 unsigned integers per buffer.
  *
- * Security:
+ * \li Security:
  *     No anticipated impact.
  *
- * Standards:
+ * \li Standards:
  *     None.
  */
 
 #include <isc/magic.h>
 #include <isc/types.h>
 
-/*
- * To make many functions be inline macros (via #define) define this.
+/*!
+ * To make many functions be inline macros (via \#define) define this.
  * If it is undefined, a function will be used.
  */
-#define ISC_BUFFER_USEINLINE 
+/* #define ISC_BUFFER_USEINLINE */
 
 ISC_LANG_BEGINDECLS
 
-/***
+/*@{*/
+/*!
  *** Magic numbers
  ***/
 #define ISC_BUFFER_MAGIC               0x42756621U     /* Buf!. */
 #define ISC_BUFFER_VALID(b)            ISC_MAGIC_VALID(b, ISC_BUFFER_MAGIC)
+/*@}*/
 
 /*
  * The following macros MUST be used only on valid buffers.  It is the
@@ -129,7 +134,8 @@ ISC_LANG_BEGINDECLS
  * another macro.)
  */
 
-/*
+/*@{*/
+/*!
  * Fundamental buffer elements.  (A through E in the introductory comment.)
  */
 #define isc_buffer_base(b)    ((void *)(b)->base)                        /*a*/
@@ -140,8 +146,10 @@ ISC_LANG_BEGINDECLS
 #define isc_buffer_used(b)    \
                ((void *)((unsigned char *)(b)->base + (b)->used))        /*d*/
 #define isc_buffer_length(b)  ((b)->length)                              /*e*/
+/*@}*/
 
-/*
+/*@{*/
+/*!
  * Derived lengths.  (Described in the introductory comment.)
  */
 #define isc_buffer_usedlength(b)       ((b)->used)                   /* d-a */
@@ -149,8 +157,9 @@ ISC_LANG_BEGINDECLS
 #define isc_buffer_remaininglength(b)  ((b)->used - (b)->current)    /* d-b */
 #define isc_buffer_activelength(b)     ((b)->active - (b)->current)  /* c-b */
 #define isc_buffer_availablelength(b)  ((b)->length - (b)->used)     /* e-d */
+/*@}*/
 
-/*
+/*!
  * Note that the buffer structure is public.  This is principally so buffer
  * operations can be implemented using macros.  Applications are strongly
  * discouraged from directly manipulating the structure.
@@ -159,14 +168,16 @@ ISC_LANG_BEGINDECLS
 struct isc_buffer {
        unsigned int            magic;
        void                   *base;
-       /* The following integers are byte offsets from 'base'. */
+       /*@{*/
+       /*! The following integers are byte offsets from 'base'. */
        unsigned int            length;
        unsigned int            used;
        unsigned int            current;
        unsigned int            active;
-       /* linkable */
+       /*@}*/
+       /*! linkable */
        ISC_LINK(isc_buffer_t)  link;
-       /* private internal elements */
+       /*! private internal elements */
        isc_mem_t              *mctx;
 };
 
@@ -177,397 +188,468 @@ struct isc_buffer {
 isc_result_t
 isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
                    unsigned int length);
-/*
- * Allocate a dynamic linkable buffer which has "length" bytes in the
+/*!<
+ * \brief Allocate a dynamic linkable buffer which has "length" bytes in the
  * data region.
  *
  * Requires:
- *     "mctx" is valid.
+ *\li  "mctx" is valid.
  *
- *     "dynbuffer" is non-NULL, and "*dynbuffer" is NULL.
+ *\li  "dynbuffer" is non-NULL, and "*dynbuffer" is NULL.
  *
  * Returns:
- *     ISC_R_SUCCESS           - success
- *     ISC_R_NOMEMORY          - no memory available
+ *\li  ISC_R_SUCCESS           - success
+ *\li  ISC_R_NOMEMORY          - no memory available
  *
  * Note:
- *     Changing the buffer's length field is not permitted.
+ *\li  Changing the buffer's length field is not permitted.
  */
 
 void
 isc_buffer_free(isc_buffer_t **dynbuffer);
-/*
- * Release resources allocated for a dynamic buffer.
+/*!<
+ * \brief Release resources allocated for a dynamic buffer.
  *
  * Requires:
- *     "dynbuffer" is not NULL.
+ *\li  "dynbuffer" is not NULL.
  *
- *     "*dynbuffer" is a valid dynamic buffer.
+ *\li  "*dynbuffer" is a valid dynamic buffer.
  *
  * Ensures:
- *     "*dynbuffer" will be NULL on return, and all memory associated with
+ *\li  "*dynbuffer" will be NULL on return, and all memory associated with
  *     the dynamic buffer is returned to the memory context used in
  *     isc_buffer_allocate().
  */
 
 void
 isc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length);
-/*
- * Make 'b' refer to the 'length'-byte region starting at base.
+/*!<
+ * \brief Make 'b' refer to the 'length'-byte region starting at base.
+ *
+ * Requires:
+ *
+ *\li  'length' > 0
+ *
+ *\li  'base' is a pointer to a sequence of 'length' bytes.
+ *
+ */
+
+void
+isc__buffer_initnull(isc_buffer_t *b);
+/*!<
+ *\brief Initialize a buffer 'b' with a null data and zero length/
+ */
+
+void
+isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length);
+/*!<
+ * \brief Make 'b' refer to the 'length'-byte region starting at base.
+ * Any existing data will be copied.
  *
  * Requires:
  *
- *     'length' > 0
+ *\li  'length' > 0 AND length >= previous length
  *
- *     'base' is a pointer to a sequence of 'length' bytes.
+ *\li  'base' is a pointer to a sequence of 'length' bytes.
  *
  */
 
 void
 isc__buffer_invalidate(isc_buffer_t *b);
-/*
- * Make 'b' an invalid buffer.
+/*!<
+ * \brief Make 'b' an invalid buffer.
  *
  * Requires:
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
  * Ensures:
- *     If assertion checking is enabled, future attempts to use 'b' without
+ *\li  If assertion checking is enabled, future attempts to use 'b' without
  *     calling isc_buffer_init() on it will cause an assertion failure.
  */
 
 void
 isc__buffer_region(isc_buffer_t *b, isc_region_t *r);
-/*
- * Make 'r' refer to the region of 'b'.
+/*!<
+ * \brief Make 'r' refer to the region of 'b'.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     'r' points to a region structure.
+ *\li  'r' points to a region structure.
  */
 
 void
 isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r);
-/*
- * Make 'r' refer to the used region of 'b'.
+/*!<
+ * \brief Make 'r' refer to the used region of 'b'.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     'r' points to a region structure.
+ *\li  'r' points to a region structure.
  */
 
 void
 isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r);
-/*
- * Make 'r' refer to the available region of 'b'.
+/*!<
+ * \brief Make 'r' refer to the available region of 'b'.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     'r' points to a region structure.
+ *\li  'r' points to a region structure.
  */
 
 void
 isc__buffer_add(isc_buffer_t *b, unsigned int n);
-/*
- * Increase the 'used' region of 'b' by 'n' bytes.
+/*!<
+ * \brief Increase the 'used' region of 'b' by 'n' bytes.
  *
  * Requires:
  *
- *     'b' is a valid buffer
+ *\li  'b' is a valid buffer
  *
- *     used + n <= length
+ *\li  used + n <= length
  *
  */
 
 void
 isc__buffer_subtract(isc_buffer_t *b, unsigned int n);
-/*
- * Decrease the 'used' region of 'b' by 'n' bytes.
+/*!<
+ * \brief Decrease the 'used' region of 'b' by 'n' bytes.
  *
  * Requires:
  *
- *     'b' is a valid buffer
+ *\li  'b' is a valid buffer
  *
- *     used >= n
+ *\li  used >= n
  *
  */
 
 void
 isc__buffer_clear(isc_buffer_t *b);
-/*
- * Make the used region empty.
+/*!<
+ * \brief Make the used region empty.
  *
  * Requires:
  *
- *     'b' is a valid buffer
+ *\li  'b' is a valid buffer
  *
  * Ensures:
  *
- *     used = 0
+ *\li  used = 0
  *
  */
 
 void
 isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r);
-/*
- * Make 'r' refer to the consumed region of 'b'.
+/*!<
+ * \brief Make 'r' refer to the consumed region of 'b'.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     'r' points to a region structure.
+ *\li  'r' points to a region structure.
  */
 
 void
 isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r);
-/*
- * Make 'r' refer to the remaining region of 'b'.
+/*!<
+ * \brief Make 'r' refer to the remaining region of 'b'.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     'r' points to a region structure.
+ *\li  'r' points to a region structure.
  */
 
 void
 isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r);
-/*
- * Make 'r' refer to the active region of 'b'.
+/*!<
+ * \brief Make 'r' refer to the active region of 'b'.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     'r' points to a region structure.
+ *\li  'r' points to a region structure.
  */
 
 void
 isc__buffer_setactive(isc_buffer_t *b, unsigned int n);
-/*
- * Sets the end of the active region 'n' bytes after current.
+/*!<
+ * \brief Sets the end of the active region 'n' bytes after current.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     current + n <= used
+ *\li  current + n <= used
  */
 
 void
 isc__buffer_first(isc_buffer_t *b);
-/*
- * Make the consumed region empty.
+/*!<
+ * \brief Make the consumed region empty.
  *
  * Requires:
  *
- *     'b' is a valid buffer
+ *\li  'b' is a valid buffer
  *
  * Ensures:
  *
- *     current == 0
+ *\li  current == 0
  *
  */
 
 void
 isc__buffer_forward(isc_buffer_t *b, unsigned int n);
-/*
- * Increase the 'consumed' region of 'b' by 'n' bytes.
+/*!<
+ * \brief Increase the 'consumed' region of 'b' by 'n' bytes.
  *
  * Requires:
  *
- *     'b' is a valid buffer
+ *\li  'b' is a valid buffer
  *
- *     current + n <= used
+ *\li  current + n <= used
  *
  */
 
 void
 isc__buffer_back(isc_buffer_t *b, unsigned int n);
-/*
- * Decrease the 'consumed' region of 'b' by 'n' bytes.
+/*!<
+ * \brief Decrease the 'consumed' region of 'b' by 'n' bytes.
  *
  * Requires:
  *
- *     'b' is a valid buffer
+ *\li  'b' is a valid buffer
  *
- *     n <= current
+ *\li  n <= current
  *
  */
 
 void
 isc_buffer_compact(isc_buffer_t *b);
-/*
- * Compact the used region by moving the remaining region so it occurs
+/*!<
+ * \brief Compact the used region by moving the remaining region so it occurs
  * at the start of the buffer.  The used region is shrunk by the size of
  * the consumed region, and the consumed region is then made empty.
  *
  * Requires:
  *
- *     'b' is a valid buffer
+ *\li  'b' is a valid buffer
  *
  * Ensures:
  *
- *     current == 0
+ *\li  current == 0
  *
- *     The size of the used region is now equal to the size of the remaining
+ *\li  The size of the used region is now equal to the size of the remaining
  *     region (as it was before the call).  The contents of the used region
  *     are those of the remaining region (as it was before the call).
  */
 
 isc_uint8_t
 isc_buffer_getuint8(isc_buffer_t *b);
-/*
- * Read an unsigned 8-bit integer from 'b' and return it.
+/*!<
+ * \brief Read an unsigned 8-bit integer from 'b' and return it.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     The length of the available region of 'b' is at least 1.
+ *\li  The length of the available region of 'b' is at least 1.
  *
  * Ensures:
  *
- *     The current pointer in 'b' is advanced by 1.
+ *\li  The current pointer in 'b' is advanced by 1.
  *
  * Returns:
  *
- *     A 8-bit unsigned integer.
+ *\li  A 8-bit unsigned integer.
  */
 
 void
 isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val);
-/*
- * Store an unsigned 8-bit integer from 'val' into 'b'.
+/*!<
+ * \brief Store an unsigned 8-bit integer from 'val' into 'b'.
  *
  * Requires:
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     The length of the unused region of 'b' is at least 1.
+ *\li  The length of the unused region of 'b' is at least 1.
  *
  * Ensures:
- *     The used pointer in 'b' is advanced by 1.
+ *\li  The used pointer in 'b' is advanced by 1.
  */
 
 isc_uint16_t
 isc_buffer_getuint16(isc_buffer_t *b);
-/*
- * Read an unsigned 16-bit integer in network byte order from 'b', convert
+/*!<
+ * \brief Read an unsigned 16-bit integer in network byte order from 'b', convert
  * it to host byte order, and return it.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     The length of the available region of 'b' is at least 2.
+ *\li  The length of the available region of 'b' is at least 2.
  *
  * Ensures:
  *
- *     The current pointer in 'b' is advanced by 2.
+ *\li  The current pointer in 'b' is advanced by 2.
  *
  * Returns:
  *
- *     A 16-bit unsigned integer.
+ *\li  A 16-bit unsigned integer.
  */
 
 void
 isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val);
-/*
- * Store an unsigned 16-bit integer in host byte order from 'val'
+/*!<
+ * \brief Store an unsigned 16-bit integer in host byte order from 'val'
  * into 'b' in network byte order.
  *
  * Requires:
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     The length of the unused region of 'b' is at least 2.
+ *\li  The length of the unused region of 'b' is at least 2.
  *
  * Ensures:
- *     The used pointer in 'b' is advanced by 2.
+ *\li  The used pointer in 'b' is advanced by 2.
  */
 
 isc_uint32_t
 isc_buffer_getuint32(isc_buffer_t *b);
-/*
- * Read an unsigned 32-bit integer in network byte order from 'b', convert
+/*!<
+ * \brief Read an unsigned 32-bit integer in network byte order from 'b', convert
  * it to host byte order, and return it.
  *
  * Requires:
  *
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     The length of the available region of 'b' is at least 4.
+ *\li  The length of the available region of 'b' is at least 4.
  *
  * Ensures:
  *
- *     The current pointer in 'b' is advanced by 4.
+ *\li  The current pointer in 'b' is advanced by 4.
  *
  * Returns:
  *
- *     A 32-bit unsigned integer.
+ *\li  A 32-bit unsigned integer.
  */
 
 void
 isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val);
-/*
- * Store an unsigned 32-bit integer in host byte order from 'val'
+/*!<
+ * \brief Store an unsigned 32-bit integer in host byte order from 'val'
  * into 'b' in network byte order.
  *
  * Requires:
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     The length of the unused region of 'b' is at least 4.
+ *\li  The length of the unused region of 'b' is at least 4.
  *
  * Ensures:
- *     The used pointer in 'b' is advanced by 4.
+ *\li  The used pointer in 'b' is advanced by 4.
+ */
+
+isc_uint64_t
+isc_buffer_getuint48(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 48-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li  'b' is a valid buffer.
+ *
+ *\li  The length of the available region of 'b' is at least 6.
+ *
+ * Ensures:
+ *
+ *\li  The current pointer in 'b' is advanced by 6.
+ *
+ * Returns:
+ *
+ *\li  A 48-bit unsigned integer (stored in a 64-bit integer).
+ */
+
+void
+isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val);
+/*!<
+ * \brief Store an unsigned 48-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li  'b' is a valid buffer.
+ *
+ *\li  The length of the unused region of 'b' is at least 6.
+ *
+ * Ensures:
+ *\li  The used pointer in 'b' is advanced by 6.
+ */
+
+void
+isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val);
+/*!<
+ * Store an unsigned 24-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li  'b' is a valid buffer.
+ *
+ *     The length of the unused region of 'b' is at least 3.
+ *
+ * Ensures:
+ *\li  The used pointer in 'b' is advanced by 3.
  */
 
 void
 isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
                   unsigned int length);
-/*
- * Copy 'length' bytes of memory at 'base' into 'b'.
+/*!<
+ * \brief Copy 'length' bytes of memory at 'base' into 'b'.
  *
  * Requires:
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     'base' points to 'length' bytes of valid memory.
+ *\li  'base' points to 'length' bytes of valid memory.
  *
  */
 
 void
 isc__buffer_putstr(isc_buffer_t *b, const char *source);
-/*
- * Copy 'source' into 'b', not including terminating NUL.
+/*!<
+ * \brief Copy 'source' into 'b', not including terminating NUL.
  *
  * Requires:
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     'source' to be a valid NULL terminated string.
+ *\li  'source' to be a valid NULL terminated string.
  *
- *     strlen(source) <= isc_buffer_available(b)
+ *\li  strlen(source) <= isc_buffer_available(b)
  */
 
 isc_result_t
 isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r);
-/*
- * Copy the contents of 'r' into 'b'.
+/*!<
+ * \brief Copy the contents of 'r' into 'b'.
  *
  * Requires:
- *     'b' is a valid buffer.
+ *\li  'b' is a valid buffer.
  *
- *     'r' is a valid region.
+ *\li  'r' is a valid region.
  *
  * Returns:
  *
- *     ISC_R_SUCCESS
- *     ISC_R_NOSPACE                   The available region of 'b' is not
+ *\li  ISC_R_SUCCESS
+ *\li  ISC_R_NOSPACE                   The available region of 'b' is not
  *                                     big enough.
  */
 
@@ -580,7 +662,7 @@ ISC_LANG_ENDDECLS
  * ones beginning with "isc__"
  */
 
-/*
+/*! \note
  * XXXDCL Something more could be done with initializing buffers that
  * point to const data.  For example, a new function, isc_buffer_initconst,
  * could be used, and a new boolean flag in the buffer structure could
@@ -614,6 +696,8 @@ ISC_LANG_ENDDECLS
                (_b)->magic = ISC_BUFFER_MAGIC; \
        } while (0)
 
+#define ISC__BUFFER_INITNULL(_b) ISC__BUFFER_INIT(_b, NULL, 0)
+
 #define ISC__BUFFER_INVALIDATE(_b) \
        do { \
                (_b)->magic = 0; \
@@ -741,6 +825,17 @@ ISC_LANG_ENDDECLS
                _cp[1] = (unsigned char)(_val2 & 0x00ffU); \
        } while (0)
 
+#define ISC__BUFFER_PUTUINT24(_b, _val) \
+       do { \
+               unsigned char *_cp; \
+               isc_uint32_t _val2 = (_val); \
+               _cp = isc_buffer_used(_b); \
+               (_b)->used += 3; \
+               _cp[0] = (unsigned char)((_val2 & 0xff0000U) >> 16); \
+               _cp[1] = (unsigned char)((_val2 & 0xff00U) >> 8); \
+               _cp[2] = (unsigned char)(_val2 & 0x00ffU); \
+       } while (0)
+
 #define ISC__BUFFER_PUTUINT32(_b, _val) \
        do { \
                unsigned char *_cp; \
@@ -755,6 +850,7 @@ ISC_LANG_ENDDECLS
 
 #if defined(ISC_BUFFER_USEINLINE)
 #define isc_buffer_init                        ISC__BUFFER_INIT
+#define isc_buffer_initnull            ISC__BUFFER_INITNULL
 #define isc_buffer_invalidate          ISC__BUFFER_INVALIDATE
 #define isc_buffer_region              ISC__BUFFER_REGION
 #define isc_buffer_usedregion          ISC__BUFFER_USEDREGION
@@ -773,9 +869,11 @@ ISC_LANG_ENDDECLS
 #define isc_buffer_putstr              ISC__BUFFER_PUTSTR
 #define isc_buffer_putuint8            ISC__BUFFER_PUTUINT8
 #define isc_buffer_putuint16           ISC__BUFFER_PUTUINT16
+#define isc_buffer_putuint24           ISC__BUFFER_PUTUINT24
 #define isc_buffer_putuint32           ISC__BUFFER_PUTUINT32
 #else
 #define isc_buffer_init                        isc__buffer_init
+#define isc_buffer_initnull            isc__buffer_initnull
 #define isc_buffer_invalidate          isc__buffer_invalidate
 #define isc_buffer_region              isc__buffer_region
 #define isc_buffer_usedregion          isc__buffer_usedregion
@@ -794,7 +892,13 @@ ISC_LANG_ENDDECLS
 #define isc_buffer_putstr              isc__buffer_putstr
 #define isc_buffer_putuint8            isc__buffer_putuint8
 #define isc_buffer_putuint16           isc__buffer_putuint16
+#define isc_buffer_putuint24           isc__buffer_putuint24
 #define isc_buffer_putuint32           isc__buffer_putuint32
 #endif
 
+/*
+ * No inline method for this one (yet).
+ */
+#define isc_buffer_putuint48           isc__buffer_putuint48
+
 #endif /* ISC_BUFFER_H */
diff --git a/lib/isc/include/isc/bufferlist.h b/lib/isc/include/isc/bufferlist.h
new file mode 100644 (file)
index 0000000..54e00c7
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: bufferlist.h,v 1.17 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_BUFFERLIST_H
+#define ISC_BUFFERLIST_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/bufferlist.h
+ *
+ *
+ *\brief       Buffer lists have no synchronization.  Clients must ensure exclusive
+ *     access.
+ *
+ * \li Reliability:
+ *     No anticipated impact.
+
+ * \li Security:
+ *     No anticipated impact.
+ *
+ * \li Standards:
+ *     None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+unsigned int
+isc_bufferlist_usedcount(isc_bufferlist_t *bl);
+/*!<
+ * \brief Return the length of the sum of all used regions of all buffers in
+ * the buffer list 'bl'
+ *
+ * Requires:
+ *
+ *\li  'bl' is not NULL.
+ *
+ * Returns:
+ *\li  sum of all used regions' lengths.
+ */
+
+unsigned int
+isc_bufferlist_availablecount(isc_bufferlist_t *bl);
+/*!<
+ * \brief Return the length of the sum of all available regions of all buffers in
+ * the buffer list 'bl'
+ *
+ * Requires:
+ *
+ *\li  'bl' is not NULL.
+ *
+ * Returns:
+ *\li  sum of all available regions' lengths.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BUFFERLIST_H */
diff --git a/lib/isc/include/isc/commandline.h b/lib/isc/include/isc/commandline.h
new file mode 100644 (file)
index 0000000..384640a
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: commandline.h,v 1.16 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_COMMANDLINE_H
+#define ISC_COMMANDLINE_H 1
+
+/*! \file isc/commandline.h */
+
+#include <isc/boolean.h>
+#include <isc/lang.h>
+#include <isc/platform.h>
+
+/*% Index into parent argv vector. */
+LIBISC_EXTERNAL_DATA extern int isc_commandline_index;
+/*% Character checked for validity. */
+LIBISC_EXTERNAL_DATA extern int isc_commandline_option;
+/*% Argument associated with option. */
+LIBISC_EXTERNAL_DATA extern char *isc_commandline_argument;
+/*% For printing error messages. */
+LIBISC_EXTERNAL_DATA extern char *isc_commandline_progname;
+/*% Print error message. */
+LIBISC_EXTERNAL_DATA extern isc_boolean_t isc_commandline_errprint;
+/*% Reset getopt. */
+LIBISC_EXTERNAL_DATA extern isc_boolean_t isc_commandline_reset;
+
+ISC_LANG_BEGINDECLS
+
+/*% parse command line */
+int
+isc_commandline_parse(int argc, char * const *argv, const char *options);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_COMMANDLINE_H */
diff --git a/lib/isc/include/isc/entropy.h b/lib/isc/include/isc/entropy.h
new file mode 100644 (file)
index 0000000..e9e59c4
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: entropy.h,v 1.32.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef ISC_ENTROPY_H
+#define ISC_ENTROPY_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/entropy.h
+ * \brief The entropy API
+ *
+ * \li MP:
+ *     The entropy object is locked internally.  All callbacks into
+ *     application-provided functions (for setup, gathering, and
+ *     shutdown of sources) are guaranteed to be called with the
+ *     entropy API lock held.  This means these functions are
+ *     not permitted to call back into the entropy API.
+ *
+ * \li Reliability:
+ *     No anticipated impact.
+ *
+ * \li Resources:
+ *     A buffer, used as an entropy pool.
+ *
+ * \li Security:
+ *     While this code is believed to implement good entropy gathering
+ *     and distribution, it has not been reviewed by a cryptographic
+ *     expert.
+ *     Since the added entropy is only as good as the sources used,
+ *     this module could hand out bad data and never know it.
+ *
+ * \li Standards:
+ *     None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*@{*/
+/*% Entropy callback function. */
+typedef isc_result_t (*isc_entropystart_t)(isc_entropysource_t *source,
+                                          void *arg, isc_boolean_t blocking);
+typedef isc_result_t (*isc_entropyget_t)(isc_entropysource_t *source,
+                                        void *arg, isc_boolean_t blocking);
+typedef void (*isc_entropystop_t)(isc_entropysource_t *source, void *arg);
+/*@}*/
+
+/***
+ *** Flags.
+ ***/
+
+/*!
+ * \brief
+ *     Extract only "good" data; return failure if there is not enough
+ *     data available and there are no sources which we can poll to get
+ *     data, or those sources are empty.
+ *
+ *
+ */
+#define ISC_ENTROPY_GOODONLY   0x00000001U
+/*!
+ * \brief
+ *     Extract as much good data as possible, but if there isn't enough
+ *     at hand, return what is available.  This flag only makes sense
+ *     when used with _GOODONLY.
+ */
+#define ISC_ENTROPY_PARTIAL    0x00000002U
+/*!
+ * \brief
+ *     Block the task until data is available.  This is contrary to the
+ *     ISC task system, where tasks should never block.  However, if
+ *     this is a special purpose application where blocking a task is
+ *     acceptable (say, an offline zone signer) this flag may be set.
+ *     This flag only makes sense when used with _GOODONLY, and will
+ *     block regardless of the setting for _PARTIAL.
+ */
+#define ISC_ENTROPY_BLOCKING   0x00000004U
+
+/*!
+ * \brief
+ *     Estimate the amount of entropy contained in the sample pool.
+ *     If this is not set, the source will be gathered and periodically
+ *     mixed into the entropy pool, but no increment in contained entropy
+ *     will be assumed.  This flag only makes sense on sample sources.
+ */
+#define ISC_ENTROPYSOURCE_ESTIMATE     0x00000001U
+
+/*
+ * For use with isc_entropy_usebestsource().
+ */
+/*!
+ * \brief
+ *     Use the keyboard as the only entropy source.
+ */
+#define ISC_ENTROPY_KEYBOARDYES                1
+/*!
+ * \brief
+ *     Never use the keyboard as an entropy source.
+ */
+#define ISC_ENTROPY_KEYBOARDNO         2
+/*!
+ * \brief
+ *     Use the keyboard as an entropy source only if opening the
+ *     random device fails.
+ */
+#define ISC_ENTROPY_KEYBOARDMAYBE      3
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp);
+/*!<
+ * \brief Create a new entropy object.
+ */
+
+void
+isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp);
+/*!<
+ * Attaches to an entropy object.
+ */
+
+void
+isc_entropy_detach(isc_entropy_t **entp);
+/*!<
+ * \brief Detaches from an entropy object.
+ */
+
+isc_result_t
+isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname);
+/*!<
+ * \brief Create a new entropy source from a file.
+ *
+ * The file is assumed to contain good randomness, and will be mixed directly
+ * into the pool with every byte adding 8 bits of entropy.
+ *
+ * The file will be put into non-blocking mode, so it may be a device file,
+ * such as /dev/random.  /dev/urandom should not be used here if it can
+ * be avoided, since it will always provide data even if it isn't good.
+ * We will make as much pseudorandom data as we need internally if our
+ * caller asks for it.
+ *
+ * If we hit end-of-file, we will stop reading from this source.  Callers
+ * who require strong random data will get failure when our pool drains.
+ * The file will never be opened/read again once EOF is reached.
+ */
+
+void
+isc_entropy_destroysource(isc_entropysource_t **sourcep);
+/*!<
+ * \brief Removes an entropy source from the entropy system.
+ */
+
+isc_result_t
+isc_entropy_createsamplesource(isc_entropy_t *ent,
+                              isc_entropysource_t **sourcep);
+/*!<
+ * \brief Create an entropy source that consists of samples.  Each sample is added
+ * to the source via isc_entropy_addsamples(), below.
+ */
+
+isc_result_t
+isc_entropy_createcallbacksource(isc_entropy_t *ent,
+                                isc_entropystart_t start,
+                                isc_entropyget_t get,
+                                isc_entropystop_t stop,
+                                void *arg,
+                                isc_entropysource_t **sourcep);
+/*!<
+ * \brief Create an entropy source that is polled via a callback.
+ *
+ * This would
+ * be used when keyboard input is used, or a GUI input method.  It can
+ * also be used to hook in any external entropy source.
+ *
+ * Samples are added via isc_entropy_addcallbacksample(), below.
+ * _addcallbacksample() is the only function which may be called from
+ * within an entropy API callback function.
+ */
+
+void
+isc_entropy_stopcallbacksources(isc_entropy_t *ent);
+/*!<
+ * \brief Call the stop functions for callback sources that have had their
+ * start functions called.
+ */
+
+/*@{*/
+isc_result_t
+isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
+                             isc_uint32_t extra);
+isc_result_t
+isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
+                     isc_uint32_t extra);
+/*!<
+ * \brief Add a sample to the sample source.
+ *
+ * The sample MUST be a timestamp
+ * that increases over time, with the exception of wrap-around for
+ * extremely high resolution timers which will quickly wrap-around
+ * a 32-bit integer.
+ *
+ * The "extra" parameter is used only to add a bit more unpredictable
+ * data.  It is not used other than included in the hash of samples.
+ *
+ * When in an entropy API callback function, _addcallbacksource() must be
+ * used.  At all other times, _addsample() must be used.
+ */
+/*@}*/
+
+isc_result_t
+isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
+                   unsigned int *returned, unsigned int flags);
+/*!<
+ * \brief Extract data from the entropy pool.  This may load the pool from various
+ * sources.
+ *
+ * Do this by stiring the pool and returning a part of hash as randomness.
+ * Note that no secrets are given away here since parts of the hash are
+ * xored together before returned.
+ *
+ * Honor the request from the caller to only return good data, any data,
+ * etc.
+ */
+
+void
+isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
+                   isc_uint32_t entropy);
+/*!<
+ * \brief Add "length" bytes in "data" to the entropy pool, incrementing the pool's
+ * entropy count by "entropy."
+ *
+ * These bytes will prime the pseudorandom portion even no entropy is actually
+ * added.
+ */
+
+void
+isc_entropy_stats(isc_entropy_t *ent, FILE *out);
+/*!<
+ * \brief Dump some (trivial) stats to the stdio stream "out".
+ */
+
+unsigned int
+isc_entropy_status(isc_entropy_t *end);
+/*
+ * Returns the number of bits the pool currently contains.  This is just
+ * an estimate.
+ */
+
+isc_result_t
+isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
+                         const char *randomfile, int use_keyboard);
+/*!<
+ * \brief Use whatever source of entropy is best.
+ *
+ * Notes:
+ *\li  If "randomfile" is not NULL, open it with
+ *     isc_entropy_createfilesource().
+ *
+ *\li  If "randomfile" is NULL and the system's random device was detected
+ *     when the program was configured and built, open that device with
+ *     isc_entropy_createfilesource().
+ *
+ *\li  If "use_keyboard" is #ISC_ENTROPY_KEYBOARDYES, then always open
+ *     the keyboard as an entropy source (possibly in addition to
+ *     "randomfile" or the random device).
+ *
+ *\li  If "use_keyboard" is #ISC_ENTROPY_KEYBOARDMAYBE, open the keyboard only
+ *     if opening the random file/device fails.  A message will be
+ *     printed describing the need for keyboard input.
+ *
+ *\li  If "use_keyboard" is #ISC_ENTROPY_KEYBOARDNO, the keyboard will
+ *     never be opened.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS if at least one source of entropy could be started.
+ *
+ *\li  #ISC_R_NOENTROPY if use_keyboard is #ISC_ENTROPY_KEYBOARDNO and
+ *     there is no random device pathname compiled into the program.
+ *
+ *\li  A return code from isc_entropy_createfilesource() or
+ *     isc_entropy_createcallbacksource().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ENTROPY_H */
index 1dc07748c21d765e87dc0d2ee590c7ce1d813b1c..efb9b5f3a11c1bf0108f1044fa5dddea5bf77b5d 100644 (file)
@@ -1,25 +1,27 @@
 /*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: error.h,v 1.13 2001/01/09 21:56:51 bwelling Exp $ */
+/* $Id: error.h,v 1.20 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_ERROR_H
 #define ISC_ERROR_H 1
 
+/*! \file isc/error.h */
+
 #include <stdarg.h>
 
 #include <isc/formatcheck.h>
@@ -29,20 +31,25 @@ ISC_LANG_BEGINDECLS
 
 typedef void (*isc_errorcallback_t)(const char *, int, const char *, va_list);
 
+/*% set unexpected error */
 void
 isc_error_setunexpected(isc_errorcallback_t);
 
+/*% set fatal error */
 void
 isc_error_setfatal(isc_errorcallback_t);
 
+/*% unexpected error */
 void
 isc_error_unexpected(const char *, int, const char *, ...)
      ISC_FORMAT_PRINTF(3, 4);
 
+/*% fatal error */
 void
 isc_error_fatal(const char *, int, const char *, ...)
      ISC_FORMAT_PRINTF(3, 4);
 
+/*% runtimecheck error */
 void
 isc_error_runtimecheck(const char *, int, const char *);
 
diff --git a/lib/isc/include/isc/event.h b/lib/isc/include/isc/event.h
new file mode 100644 (file)
index 0000000..68fabb2
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: event.h,v 1.34 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_EVENT_H
+#define ISC_EVENT_H 1
+
+/*! \file isc/event.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*****
+ ***** Events.
+ *****/
+
+typedef void (*isc_eventdestructor_t)(isc_event_t *);
+
+#define ISC_EVENT_COMMON(ltype)                \
+       size_t                          ev_size; \
+       unsigned int                    ev_attributes; \
+       void *                          ev_tag; \
+       isc_eventtype_t                 ev_type; \
+       isc_taskaction_t                ev_action; \
+       void *                          ev_arg; \
+       void *                          ev_sender; \
+       isc_eventdestructor_t           ev_destroy; \
+       void *                          ev_destroy_arg; \
+       ISC_LINK(ltype)                 ev_link
+
+/*%
+ * Attributes matching a mask of 0x000000ff are reserved for the task library's
+ * definition.  Attributes of 0xffffff00 may be used by the application
+ * or non-ISC libraries.
+ */
+#define ISC_EVENTATTR_NOPURGE          0x00000001
+
+/*%
+ * The ISC_EVENTATTR_CANCELED attribute is intended to indicate
+ * that an event is delivered as a result of a canceled operation
+ * rather than successful completion, by mutual agreement
+ * between the sender and receiver.  It is not set or used by
+ * the task system.
+ */
+#define ISC_EVENTATTR_CANCELED         0x00000002
+
+#define ISC_EVENT_INIT(event, sz, at, ta, ty, ac, ar, sn, df, da) \
+do { \
+       (event)->ev_size = (sz); \
+       (event)->ev_attributes = (at); \
+       (event)->ev_tag = (ta); \
+       (event)->ev_type = (ty); \
+       (event)->ev_action = (ac); \
+       (event)->ev_arg = (ar); \
+       (event)->ev_sender = (sn); \
+       (event)->ev_destroy = (df); \
+       (event)->ev_destroy_arg = (da); \
+       ISC_LINK_INIT((event), ev_link); \
+} while (0)
+
+/*%
+ * This structure is public because "subclassing" it may be useful when
+ * defining new event types.
+ */
+struct isc_event {
+       ISC_EVENT_COMMON(struct isc_event);
+};
+
+#define ISC_EVENTTYPE_FIRSTEVENT       0x00000000
+#define ISC_EVENTTYPE_LASTEVENT                0xffffffff
+
+#define ISC_EVENT_PTR(p) ((isc_event_t **)(void *)(p))
+
+ISC_LANG_BEGINDECLS
+
+isc_event_t *
+isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+                  isc_taskaction_t action, const void *arg, size_t size);
+/*%<
+ * Allocate an event structure. 
+ *
+ * Allocate and initialize in a structure with initial elements
+ * defined by:
+ *
+ * \code
+ *     struct {
+ *             ISC_EVENT_COMMON(struct isc_event);
+ *             ...
+ *     };
+ * \endcode
+ *     
+ * Requires:
+ *\li  'size' >= sizeof(struct isc_event)
+ *\li  'action' to be non NULL
+ *
+ * Returns:
+ *\li  a pointer to a initialized structure of the requested size.
+ *\li  NULL if unable to allocate memory.
+ */
+
+void
+isc_event_free(isc_event_t **);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_EVENT_H */
diff --git a/lib/isc/include/isc/eventclass.h b/lib/isc/include/isc/eventclass.h
new file mode 100644 (file)
index 0000000..9e6c145
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: eventclass.h,v 1.18 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_EVENTCLASS_H
+#define ISC_EVENTCLASS_H 1
+
+/*! \file isc/eventclass.h
+ ***** Registry of Predefined Event Type Classes
+ *****/
+
+/*%
+ * An event class is an unsigned 16 bit number.  Each class may contain up
+ * to 65536 events.  An event type is formed by adding the event number
+ * within the class to the class number.
+ *
+ */
+
+#define ISC_EVENTCLASS(eclass)         ((eclass) << 16)
+
+/*@{*/
+/*!
+ * Classes < 1024 are reserved for ISC use.
+ * Event classes >= 1024 and <= 65535 are reserved for application use.
+ */
+
+#define        ISC_EVENTCLASS_TASK             ISC_EVENTCLASS(0)
+#define        ISC_EVENTCLASS_TIMER            ISC_EVENTCLASS(1)
+#define        ISC_EVENTCLASS_SOCKET           ISC_EVENTCLASS(2)
+#define        ISC_EVENTCLASS_FILE             ISC_EVENTCLASS(3)
+#define        ISC_EVENTCLASS_DNS              ISC_EVENTCLASS(4)
+#define        ISC_EVENTCLASS_APP              ISC_EVENTCLASS(5)
+#define        ISC_EVENTCLASS_OMAPI            ISC_EVENTCLASS(6)
+#define        ISC_EVENTCLASS_RATELIMITER      ISC_EVENTCLASS(7)
+#define        ISC_EVENTCLASS_ISCCC            ISC_EVENTCLASS(8)
+/*@}*/
+
+#endif /* ISC_EVENTCLASS_H */
index b2d9e8f5126aaf1b747d603f9f87e21765a9689a..c9457343e0555a82c6dda78650ae8bff6f3a2fc6 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2000, 2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: file.h,v 1.27.18.2 2005/04/29 00:16:54 marka Exp $ */
+/* $Id: file.h,v 1.33.332.2 2009/01/18 23:47:41 tbox Exp $ */
 
 #ifndef ISC_FILE_H
 #define ISC_FILE_H 1
 
-/*! \file */
+/*! \file isc/file.h */
 
 #include <stdio.h>
 
 ISC_LANG_BEGINDECLS
 
 isc_result_t
-isc_file_settime(const char *file, isc_time_t *mtime);
+isc_file_settime(const char *file, isc_time_t *time);
 
 isc_result_t
-isc_file_getmodtime(const char *file, isc_time_t *mtime);
+isc_file_getmodtime(const char *file, isc_time_t *time);
 /*!<
- * \brief Get the time of last modication of a file.
+ * \brief Get the time of last modification of a file.
  *
  * Notes:
  *\li  The time that is set is relative to the (OS-specific) epoch, as are
@@ -204,7 +204,7 @@ isc_result_t
 isc_file_progname(const char *filename, char *buf, size_t buflen);
 /*!<
  * \brief Given an operating system specific file name "filename"
- * referring to a program, return the canonical program name. 
+ * referring to a program, return the canonical program name.
  *
  *
  * Any directory prefix or executable file name extension (if
index e9b91698e979a877957b95aec3f20b5bb15901b0..51ce3cac25dfd984aecd02b3a1873d091785c506 100644 (file)
@@ -1,29 +1,35 @@
 /*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2000, 2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: formatcheck.h,v 1.6 2001/01/09 21:56:55 bwelling Exp $ */
+/* $Id: formatcheck.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_FORMATCHECK_H
 #define ISC_FORMATCHECK_H 1
 
-/*
- * fmt is the location of the format string parameter.
- * args is the location of the first argument (or 0 for no argument checking).
- * Note: the first parameter is 1, not 0.
+/*! \file isc/formatcheck.h */
+
+/*%
+ * ISC_FORMAT_PRINTF().
+ *
+ * \li fmt is the location of the format string parameter.
+ * \li args is the location of the first argument (or 0 for no argument checking).
+ * 
+ * Note:
+ * \li The first parameter is 1, not 0.
  */
 #ifdef __GNUC__
 #define ISC_FORMAT_PRINTF(fmt, args) __attribute__((__format__(__printf__, fmt, args)))
diff --git a/lib/isc/include/isc/fsaccess.h b/lib/isc/include/isc/fsaccess.h
new file mode 100644 (file)
index 0000000..3b455e5
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: fsaccess.h,v 1.14.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef ISC_FSACCESS_H
+#define ISC_FSACCESS_H 1
+
+/*! \file isc/fsaccess.h
+ * \brief The ISC filesystem access module encapsulates the setting of file
+ * and directory access permissions into one API that is meant to be
+ * portable to multiple operating systems.
+ *
+ * The two primary operating system flavors that are initially accommodated
+ * are POSIX and Windows NT 4.0 and later.  The Windows NT access model is
+ * considerable more flexible than POSIX's model (as much as I am loathe to
+ * admit it), and so the ISC API has a higher degree of complexity than would
+ * be needed to simply address POSIX's needs.
+ *
+ * The full breadth of NT's flexibility is not available either, for the
+ * present time.  Much of it is to provide compatibility with what Unix
+ * programmers are expecting.  This is also due to not yet really needing all
+ * of the functionality of an NT system (or, for that matter, a POSIX system)
+ * in BIND9, and so resolving how to handle the various incompatibilities has
+ * been a purely theoretical exercise with no operational experience to
+ * indicate how flawed the thinking may be.
+ *
+ * Some of the more notable dumbing down of NT for this API includes:
+ *
+ *\li   Each of FILE_READ_DATA and FILE_READ_EA are set with #ISC_FSACCESS_READ.
+ *
+ * \li  All of FILE_WRITE_DATA, FILE_WRITE_EA and FILE_APPEND_DATA are
+ *     set with #ISC_FSACCESS_WRITE.  FILE_WRITE_ATTRIBUTES is not set
+ *     so as to be consistent with Unix, where only the owner of the file
+ *     or the superuser can change the attributes/mode of a file.
+ *
+ * \li  Both of FILE_ADD_FILE and FILE_ADD_SUBDIRECTORY are set with
+ *     #ISC_FSACCESS_CREATECHILD.  This is similar to setting the WRITE
+ *     permission on a Unix directory.
+ *
+ * \li  SYNCHRONIZE is always set for files and directories, unless someone
+ *     can give me a reason why this is a bad idea.
+ *
+ * \li  READ_CONTROL and FILE_READ_ATTRIBUTES are always set; this is
+ *     consistent with Unix, where any file or directory can be stat()'d
+ *     unless the directory path disallows complete access somewhere along
+ *     the way.
+ *
+ * \li  WRITE_DAC is only set for the owner.  This too is consistent with
+ *     Unix, and is tighter security than allowing anyone else to be
+ *     able to set permissions.
+ *
+ * \li  DELETE is only set for the owner.  On Unix the ability to delete
+ *     a file is controlled by the directory permissions, but it isn't
+ *     currently clear to me what happens on NT if the directory has
+ *     FILE_DELETE_CHILD set but a file within it does not have DELETE
+ *     set.  Always setting DELETE on the file/directory for the owner
+ *     gives maximum flexibility to the owner without exposing the
+ *     file to deletion by others.
+ *
+ * \li  WRITE_OWNER is never set.  This too is consistent with Unix,
+ *     and is also tighter security than allowing anyone to change the
+ *     ownership of the file apart from the superu..ahem, Administrator.
+ *
+ * \li  Inheritance is set to NO_INHERITANCE.
+ *
+ * Unix's dumbing down includes:
+ *
+ * \li  The sticky bit cannot be set.
+ *
+ * \li  setuid and setgid cannot be set.
+ *
+ * \li  Only regular files and directories can be set.
+ *
+ * The rest of this comment discusses a few of the incompatibilities
+ * between the two systems that need more thought if this API is to
+ * be extended to accommodate them.
+ *
+ * The Windows standard access right "DELETE" doesn't have a direct
+ * equivalent in the Unix world, so it isn't clear what should be done
+ * with it.
+ *
+ * The Unix sticky bit is not supported.  While NT does have a concept
+ * of allowing users to create files in a directory but not delete or
+ * rename them, it does not have a concept of allowing them to be deleted
+ * if they are owned by the user trying to delete/rename.  While it is
+ * probable that something could be cobbled together in NT 5 with inheritance,
+ * it can't really be done in NT 4 as a single property that you could
+ * set on a directory.  You'd need to coordinate something with file creation
+ * so that every file created had DELETE set for the owner but noone else.
+ *
+ * On Unix systems, setting #ISC_FSACCESS_LISTDIRECTORY sets READ.
+ * ... setting either #ISC_FSACCESS_CREATECHILD or #ISC_FSACCESS_DELETECHILD
+ *      sets WRITE.
+ * ... setting #ISC_FSACCESS_ACCESSCHILD sets EXECUTE.
+ *
+ * On NT systems, setting #ISC_FSACCESS_LISTDIRECTORY sets FILE_LIST_DIRECTORY.
+ * ... setting #ISC_FSACCESS_CREATECHILD sets FILE_CREATE_CHILD independently.
+ * ... setting #ISC_FSACCESS_DELETECHILD sets FILE_DELETE_CHILD independently.
+ * ... setting #ISC_FSACCESS_ACCESSCHILD sets FILE_TRAVERSE.
+ *
+ * Unresolved:                                                 XXXDCL
+ * \li  What NT access right controls the ability to rename a file?
+ * \li  How does DELETE work?  If a directory has FILE_DELETE_CHILD but a
+ *      file or directory within it does not have DELETE, is that file
+ *     or directory deletable?
+ * \li  To implement isc_fsaccess_get(), mapping an existing Unix permission
+ *     mode_t back to an isc_fsaccess_t is pretty trivial; however, mapping
+ *     an NT DACL could be impossible to do in a responsible way.
+ * \li  Similarly, trying to implement the functionality of being able to
+ *     say "add group writability to whatever permissions already exist"
+ *     could be tricky on NT because of the order-of-entry issue combined
+ *     with possibly having one or more matching ACEs already explicitly
+ *     granting or denying access.  Because this functionality is
+ *     not yet needed by the ISC, no code has been written to try to
+ *     solve this problem.
+ */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*
+ * Trustees.
+ */
+#define ISC_FSACCESS_OWNER     0x1 /*%< User account. */
+#define ISC_FSACCESS_GROUP     0x2 /*%< Primary group owner. */
+#define ISC_FSACCESS_OTHER     0x4 /*%< Not the owner or the group owner. */
+#define ISC_FSACCESS_WORLD     0x7 /*%< User, Group, Other. */
+
+/*
+ * Types of permission.
+ */
+#define ISC_FSACCESS_READ              0x00000001 /*%< File only. */
+#define ISC_FSACCESS_WRITE             0x00000002 /*%< File only. */
+#define ISC_FSACCESS_EXECUTE           0x00000004 /*%< File only. */
+#define ISC_FSACCESS_CREATECHILD       0x00000008 /*%< Dir only. */
+#define ISC_FSACCESS_DELETECHILD       0x00000010 /*%< Dir only. */
+#define ISC_FSACCESS_LISTDIRECTORY     0x00000020 /*%< Dir only. */
+#define ISC_FSACCESS_ACCESSCHILD       0x00000040 /*%< Dir only. */
+
+/*%
+ * Adding any permission bits beyond 0x200 would mean typedef'ing
+ * isc_fsaccess_t as isc_uint64_t, and redefining this value to
+ * reflect the new range of permission types, Probably to 21 for
+ * maximum flexibility.  The number of bits has to accommodate all of
+ * the permission types, and three full sets of them have to fit
+ * within an isc_fsaccess_t.
+ */
+#define ISC__FSACCESS_PERMISSIONBITS 10
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access);
+
+void
+isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access);
+
+isc_result_t
+isc_fsaccess_set(const char *path, isc_fsaccess_t access);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_FSACCESS_H */
diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h
new file mode 100644 (file)
index 0000000..da30a19
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hash.h,v 1.10.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef ISC_HASH_H
+#define ISC_HASH_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/hash.h
+ *
+ * \brief The hash API
+ *     provides an unpredictable hash value for variable length data.
+ *     A hash object contains a random vector (which is hidden from clients
+ *     of this API) to make the actual hash value unpredictable.
+ *
+ *     The algorithm used in the API guarantees the probability of hash
+ *     collision; in the current implementation, as long as the values stored
+ *     in the random vector are unpredictable, the probability of hash
+ *     collision between arbitrary two different values is at most 1/2^16.
+ *
+ *     Although the API is generic about the hash keys, it mainly expects
+ *     DNS names (and sometimes IPv4/v6 addresses) as inputs.  It has an
+ *     upper limit of the input length, and may run slow to calculate the
+ *     hash values for large inputs.
+ *
+ *     This API is designed to be general so that it can provide multiple
+ *     different hash contexts that have different random vectors.  However,
+ *     it should be typical to have a single context for an entire system.
+ *     To support such cases, the API also provides a single-context mode.
+ *
+ * \li MP:
+ *     The hash object is almost read-only.  Once the internal random vector
+ *     is initialized, no write operation will occur, and there will be no
+ *     need to lock the object to calculate actual hash values.
+ *
+ * \li Reliability:
+ *     In some cases this module uses low-level data copy to initialize the
+ *     random vector.  Errors in this part are likely to crash the server or
+ *     corrupt memory.
+ *
+ * \li Resources:
+ *     A buffer, used as a random vector for calculating hash values.
+ *
+ * \li Security:
+ *     This module intends to provide unpredictable hash values in
+ *     adversarial environments in order to avoid denial of service attacks
+ *     to hash buckets.
+ *     Its unpredictability relies on the quality of entropy to build the
+ *     random vector.
+ *
+ * \li Standards:
+ *     None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/types.h>
+
+/***
+ *** Functions
+ ***/
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, unsigned int limit,
+                  isc_hash_t **hctx);
+isc_result_t
+isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit);
+/*!<
+ * \brief Create a new hash object.
+ *
+ * isc_hash_ctxcreate() creates a different object.
+ *
+ * isc_hash_create() creates a module-internal object to support the
+ * single-context mode.  It should be called only once.
+ *
+ * 'entropy' must be NULL or a valid entropy object.  If 'entropy' is NULL,
+ * pseudo random values will be used to build the random vector, which may
+ * weaken security.
+ *
+ * 'limit' specifies the maximum number of hash keys.  If it is too large,
+ * these functions may fail.
+ */
+
+void
+isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp);
+/*!<
+ * \brief Attach to a hash object.
+ *
+ * This function is only necessary for the multiple-context mode.
+ */
+
+void
+isc_hash_ctxdetach(isc_hash_t **hctxp);
+/*!<
+ * \brief Detach from a hash object.
+ *
+ * This function  is for the multiple-context mode, and takes a valid
+ * hash object as an argument.
+ */
+
+void
+isc_hash_destroy(void);
+/*!<
+ * \brief This function is for the single-context mode, and is expected to be used
+ * as a counterpart of isc_hash_create().
+ *
+ * A valid module-internal hash object must have been created, and this
+ * function should be called only once.
+ */
+
+/*@{*/
+void
+isc_hash_ctxinit(isc_hash_t *hctx);
+void
+isc_hash_init(void);
+/*!<
+ * \brief Initialize a hash object.
+ *
+ * It fills in the random vector with a proper
+ * source of entropy, which is typically from the entropy object specified
+ * at the creation.  Thus, it is desirable to call these functions after
+ * initializing the entropy object with some good entropy sources.
+ *
+ * These functions should be called before the first hash calculation.
+ *
+ * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash
+ * object as an argument.
+ *
+ * isc_hash_init() is for the single-context mode.  A valid module-internal
+ * hash object must have been created, and this function should be called only
+ * once.
+ */
+/*@}*/
+
+/*@{*/
+unsigned int
+isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
+                unsigned int keylen, isc_boolean_t case_sensitive);
+unsigned int
+isc_hash_calc(const unsigned char *key, unsigned int keylen,
+             isc_boolean_t case_sensitive);
+/*!<
+ * \brief Calculate a hash value.
+ *
+ * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash
+ * object as an argument.
+ *
+ * isc_hash_init() is for the single-context mode.  A valid module-internal
+ * hash object must have been created.
+ *
+ * 'key' is the hash key, which is a variable length buffer.
+ *
+ * 'keylen' specifies the key length, which must not be larger than the limit
+ * specified for the corresponding hash object.
+ *
+ * 'case_sensitive' specifies whether the hash key should be treated as
+ * case_sensitive values.  It should typically be ISC_FALSE if the hash key
+ * is a DNS name.
+ */
+/*@}*/
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HASH_H */
diff --git a/lib/isc/include/isc/heap.h b/lib/isc/include/isc/heap.h
new file mode 100644 (file)
index 0000000..82c5982
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: heap.h,v 1.24.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef ISC_HEAP_H
+#define ISC_HEAP_H 1
+
+/*! \file isc/heap.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * The comparison function returns ISC_TRUE if the first argument has
+ * higher priority than the second argument, and ISC_FALSE otherwise.
+ */
+typedef isc_boolean_t (*isc_heapcompare_t)(void *, void *);
+
+/*%
+ * The index function allows the client of the heap to receive a callback
+ * when an item's index number changes.  This allows it to maintain
+ * sync with its external state, but still delete itself, since deletions
+ * from the heap require the index be provided.
+ */
+typedef void (*isc_heapindex_t)(void *, unsigned int);
+
+/*%
+ * The heapaction function is used when iterating over the heap.
+ *
+ * NOTE:  The heap structure CANNOT BE MODIFIED during the call to
+ * isc_heap_foreach().
+ */
+typedef void (*isc_heapaction_t)(void *, void *);
+
+typedef struct isc_heap isc_heap_t;
+
+isc_result_t
+isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare,
+               isc_heapindex_t index, unsigned int size_increment,
+               isc_heap_t **heapp);
+/*!<
+ * \brief Create a new heap.  The heap is implemented using a space-efficient
+ * storage method.  When the heap elements are deleted space is not freed
+ * but will be reused when new elements are inserted.
+ *
+ * Requires:
+ *\li  "mctx" is valid.
+ *\li  "compare" is a function which takes two void * arguments and
+ *     returns ISC_TRUE if the first argument has a higher priority than
+ *     the second, and ISC_FALSE otherwise.
+ *\li  "index" is a function which takes a void *, and an unsigned int
+ *     argument.  This function will be called whenever an element's
+ *     index value changes, so it may continue to delete itself from the
+ *     heap.  This option may be NULL if this functionality is unneeded.
+ *\li  "size_increment" is a hint about how large the heap should grow
+ *     when resizing is needed.  If this is 0, a default size will be
+ *     used, which is currently 1024, allowing space for an additional 1024
+ *     heap elements to be inserted before adding more space.
+ *\li  "heapp" is not NULL, and "*heap" is NULL.
+ *
+ * Returns:
+ *\li  ISC_R_SUCCESS           - success
+ *\li  ISC_R_NOMEMORY          - insufficient memory
+ */
+
+void
+isc_heap_destroy(isc_heap_t **heapp);
+/*!<
+ * \brief Destroys a heap.
+ *
+ * Requires:
+ *\li  "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ */
+
+isc_result_t
+isc_heap_insert(isc_heap_t *heap, void *elt);
+/*!<
+ * \brief Inserts a new element into a heap.
+ *
+ * Requires:
+ *\li  "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ */
+
+void
+isc_heap_delete(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Deletes an element from a heap, by element index.
+ *
+ * Requires:
+ *\li  "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li  "index" is a valid element index, as provided by the "index" callback
+ *     provided during heap creation.
+ */
+
+void
+isc_heap_increased(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Indicates to the heap that an element's priority has increased.
+ * This function MUST be called whenever an element has increased in priority.
+ *
+ * Requires:
+ *\li  "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li  "index" is a valid element index, as provided by the "index" callback
+ *     provided during heap creation.
+ */
+
+void
+isc_heap_decreased(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Indicates to the heap that an element's priority has decreased.
+ * This function MUST be called whenever an element has decreased in priority.
+ *
+ * Requires:
+ *\li  "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li  "index" is a valid element index, as provided by the "index" callback
+ *     provided during heap creation.
+ */
+
+void *
+isc_heap_element(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Returns the element for a specific element index.
+ *
+ * Requires:
+ *\li  "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li  "index" is a valid element index, as provided by the "index" callback
+ *     provided during heap creation.
+ *
+ * Returns:
+ *\li  A pointer to the element for the element index.
+ */
+
+void
+isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap);
+/*!<
+ * \brief Iterate over the heap, calling an action for each element.  The
+ * order of iteration is not sorted.
+ *
+ * Requires:
+ *\li  "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li  "action" is not NULL, and is a function which takes two arguments.
+ *     The first is a void *, representing the element, and the second is
+ *     "uap" as provided to isc_heap_foreach.
+ *\li  "uap" is a caller-provided argument, and may be NULL.
+ *
+ * Note:
+ *\li  The heap structure CANNOT be modified during this iteration.  The only
+ *     safe function to call while iterating the heap is isc_heap_element().
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HEAP_H */
diff --git a/lib/isc/include/isc/hex.h b/lib/isc/include/isc/hex.h
new file mode 100644 (file)
index 0000000..a5e2f53
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hex.h,v 1.13 2008/09/25 04:02:39 tbox Exp $ */
+
+#ifndef ISC_HEX_H
+#define ISC_HEX_H 1
+
+/*! \file isc/hex.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_hex_totext(isc_region_t *source, int wordlength,
+              const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into hex encoded text.
+ *
+ * Notes:
+ *\li  The hex encoded text in 'target' will be divided into
+ *     words of at most 'wordlength' characters, separated by
+ *     the 'wordbreak' string.  No parentheses will surround
+ *     the text.
+ *
+ * Requires:
+ *\li  'source' is a region containing binary data
+ *\li  'target' is a text buffer containing available space
+ *\li  'wordbreak' points to a null-terminated string of
+ *             zero or more whitespace characters
+ *
+ * Ensures:
+ *\li  target will contain the hex encoded version of the data
+ *     in source.  The 'used' pointer in target will be advanced as
+ *     necessary.
+ */
+
+isc_result_t
+isc_hex_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated hex string.
+ *
+ * Requires:
+ *\li  'cstr' is non-null.
+ *\li  'target' is a valid buffer.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS  -- the entire decoded representation of 'cstring'
+ *                        fit in 'target'.
+ *\li  #ISC_R_BADHEX -- 'cstr' is not a valid hex encoding.
+ *
+ *     Other error returns are any possible error code from:
+ *             isc_lex_create(),
+ *             isc_lex_openbuffer(),
+ *             isc_hex_tobuffer().
+ */
+
+isc_result_t
+isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert hex encoded text from a lexer context into data.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer context
+ *\li  'target' is a buffer containing binary data
+ *\li  'length' is an integer
+ *
+ * Ensures:
+ *\li  target will contain the data represented by the hex encoded
+ *     string parsed by the lexer.  No more than length bytes will be read,
+ *     if length is positive.  The 'used' pointer in target will be
+ *     advanced as necessary.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HEX_H */
diff --git a/lib/isc/include/isc/hmacmd5.h b/lib/isc/include/isc/hmacmd5.h
new file mode 100644 (file)
index 0000000..fab9c58
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hmacmd5.h,v 1.12 2007/06/19 23:47:18 tbox Exp $ */
+
+/*! \file isc/hmacmd5.h
+ * \brief This is the header file for the HMAC-MD5 keyed hash algorithm
+ * described in RFC2104.
+ */
+
+#ifndef ISC_HMACMD5_H
+#define ISC_HMACMD5_H 1
+
+#include <isc/lang.h>
+#include <isc/md5.h>
+#include <isc/types.h>
+
+#define ISC_HMACMD5_KEYLENGTH 64
+
+typedef struct {
+       isc_md5_t md5ctx;
+       unsigned char key[ISC_HMACMD5_KEYLENGTH];
+} isc_hmacmd5_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
+                unsigned int len);
+
+void
+isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx);
+
+void
+isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
+                  unsigned int len);
+
+void
+isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest);
+
+isc_boolean_t
+isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest);
+
+isc_boolean_t
+isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HMACMD5_H */
diff --git a/lib/isc/include/isc/hmacsha.h b/lib/isc/include/isc/hmacsha.h
new file mode 100644 (file)
index 0000000..362b37f
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2005-2007  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: hmacsha.h,v 1.7 2007/06/19 23:47:18 tbox Exp $ */
+
+/*! \file isc/hmacsha.h
+ * This is the header file for the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256,
+ * HMAC-SHA334 and HMAC-SHA512 hash algorithm described in RFC 2104.
+ */
+
+#ifndef ISC_HMACSHA_H
+#define ISC_HMACSHA_H 1
+
+#include <isc/lang.h>
+#include <isc/sha1.h>
+#include <isc/sha2.h>
+#include <isc/types.h>
+
+#define ISC_HMACSHA1_KEYLENGTH ISC_SHA1_BLOCK_LENGTH
+#define ISC_HMACSHA224_KEYLENGTH ISC_SHA224_BLOCK_LENGTH
+#define ISC_HMACSHA256_KEYLENGTH ISC_SHA256_BLOCK_LENGTH
+#define ISC_HMACSHA384_KEYLENGTH ISC_SHA384_BLOCK_LENGTH
+#define ISC_HMACSHA512_KEYLENGTH ISC_SHA512_BLOCK_LENGTH
+
+typedef struct {
+       isc_sha1_t sha1ctx;
+       unsigned char key[ISC_HMACSHA1_KEYLENGTH];
+} isc_hmacsha1_t;
+
+typedef struct {
+       isc_sha224_t sha224ctx;
+       unsigned char key[ISC_HMACSHA224_KEYLENGTH];
+} isc_hmacsha224_t;
+
+typedef struct {
+       isc_sha256_t sha256ctx;
+       unsigned char key[ISC_HMACSHA256_KEYLENGTH];
+} isc_hmacsha256_t;
+
+typedef struct {
+       isc_sha384_t sha384ctx;
+       unsigned char key[ISC_HMACSHA384_KEYLENGTH];
+} isc_hmacsha384_t;
+
+typedef struct {
+       isc_sha512_t sha512ctx;
+       unsigned char key[ISC_HMACSHA512_KEYLENGTH];
+} isc_hmacsha512_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
+                 unsigned int len);
+
+void
+isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx);
+
+void
+isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
+                   unsigned int len);
+
+void
+isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
+                   unsigned int len);
+
+void
+isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx);
+
+void
+isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
+                     unsigned int len);
+
+void
+isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
+                   unsigned int len);
+
+void
+isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx);
+
+void
+isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
+                     unsigned int len);
+
+void
+isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
+                   unsigned int len);
+
+void
+isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx);
+
+void
+isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
+                     unsigned int len);
+
+void
+isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len);
+
+
+void
+isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
+                   unsigned int len);
+
+void
+isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx);
+
+void
+isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
+                     unsigned int len);
+
+void
+isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len);
+
+isc_boolean_t
+isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_HMACSHA_H */
diff --git a/lib/isc/include/isc/httpd.h b/lib/isc/include/isc/httpd.h
new file mode 100644 (file)
index 0000000..ba7f900
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2006-2008  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: httpd.h,v 1.9 2008/08/08 05:06:49 marka Exp $ */
+
+#ifndef ISC_HTTPD_H
+#define ISC_HTTPD_H 1
+
+/*! \file */
+
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/types.h>
+#include <isc/mutex.h>
+#include <isc/task.h>
+
+#define HTTPD_EVENTCLASS               ISC_EVENTCLASS(4300)
+#define HTTPD_SHUTDOWN                 (HTTPD_EVENTCLASS + 0x0001)
+
+#define ISC_HTTPDMGR_FLAGSHUTTINGDOWN  0x00000001
+
+/*
+ * Create a new http daemon which will send, once every time period,
+ * a http-like header followed by HTTP data.
+ */
+isc_result_t
+isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
+                   isc_httpdclientok_t *client_ok,
+                   isc_httpdondestroy_t *ondestory, void *cb_arg,
+                   isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp);
+
+void
+isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdp);
+
+isc_result_t
+isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url,
+                   isc_httpdaction_t *func, void *arg);
+
+isc_result_t
+isc_httpd_response(isc_httpd_t *httpd);
+
+isc_result_t
+isc_httpd_addheader(isc_httpd_t *httpd, const char *name,
+                   const char *val);
+
+isc_result_t
+isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val);
+
+isc_result_t isc_httpd_endheaders(isc_httpd_t *httpd);
+
+#endif /* ISC_HTTPD_H */
index 3d5eef6e56d7b2e3332515e919a2b820bb385140..26d5dfb853900eed771f65f6e4bb7fa6c477f5f8 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: interfaceiter.h,v 1.10 2001/01/09 21:57:01 bwelling Exp $ */
+/* $Id: interfaceiter.h,v 1.17 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_INTERFACEITER_H
 #define ISC_INTERFACEITER_H 1
  ***** Module Info
  *****/
 
-/*
- * Interface iterator
- *
- * Iterate over the list of network interfaces.
+/*! \file isc/interfaceiter.h
+ * \brief Iterates over the list of network interfaces.
  *
  * Interfaces whose address family is not supported are ignored and never
  * returned by the iterator.  Interfaces whose netmask, interface flags,
 #include <isc/netaddr.h>
 #include <isc/types.h>
 
-/*
- * Public structure describing a network interface.
+/*!
+ * \brief Public structure describing a network interface.
  */
 
 struct isc_interface {
-       char name[32];                  /* Interface name, null-terminated. */
-       unsigned int af;                /* Address family. */
-       isc_netaddr_t address;          /* Local address. */
-       isc_netaddr_t netmask;          /* Network mask. */
-       isc_netaddr_t broadcast;        /* Broadcast address. */
-       isc_netaddr_t dstaddress;       /* Destination address
-                                          (point-to-point only). */
-       isc_uint32_t flags;             /* Flags; see below. */
+       char name[32];                  /*%< Interface name, null-terminated. */
+       unsigned int af;                /*%< Address family. */
+       isc_netaddr_t address;          /*%< Local address. */
+       isc_netaddr_t netmask;          /*%< Network mask. */
+       isc_netaddr_t dstaddress;       /*%< Destination address (point-to-point only). */
+       isc_uint32_t flags;             /*%< Flags; see INTERFACE flags. */
 };
 
-/* Interface flags. */
+/*@{*/
+/*! Interface flags. */
 
-#define INTERFACE_F_UP                 0x00000001U /* Interface is up */
-#define INTERFACE_F_POINTTOPOINT       0x00000002U /* this is point-to-point interface*/
-#define INTERFACE_F_LOOPBACK           0x00000004U /* this is loopback interface */
-#define INTERFACE_F_BROADCAST          0x00000008U /* Broadcast is  supported */
-#define INTERFACE_F_MULTICAST          0x00000010U /* multicast is supported */
+#define INTERFACE_F_UP                 0x00000001U
+#define INTERFACE_F_POINTTOPOINT       0x00000002U
+#define INTERFACE_F_LOOPBACK           0x00000004U
+/*@}*/
 
 /***
  *** Functions
@@ -77,59 +73,59 @@ ISC_LANG_BEGINDECLS
 
 isc_result_t
 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp);
-/*
- * Create an iterator for traversing the operating system's list
+/*!<
+ * \brief Create an iterator for traversing the operating system's list
  * of network interfaces.
  *
  * Returns:
- *     ISC_R_SUCCESS
- *     ISC_R_NOMEMORY
- *     Various network-related errors
+ *\li  #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ *\li  Various network-related errors
  */
 
 isc_result_t
 isc_interfaceiter_first(isc_interfaceiter_t *iter);
-/*
- * Position the iterator on the first interface.
+/*!<
+ * \brief Position the iterator on the first interface.
  *
  * Returns:
- *     ISC_R_SUCCESS           Success.
- *     ISC_R_NOMORE            There are no interfaces.
+ *\li  #ISC_R_SUCCESS          Success.
+ *\li  #ISC_R_NOMORE           There are no interfaces.
  */
 
 isc_result_t
 isc_interfaceiter_current(isc_interfaceiter_t *iter,
                          isc_interface_t *ifdata);
-/*
- * Get information about the interface the iterator is currently
+/*!<
+ * \brief Get information about the interface the iterator is currently
  * positioned at and store it at *ifdata.
  *
  * Requires:
- *     The iterator has been successfully positioned using
+ *\li  The iterator has been successfully positioned using
  *     isc_interface_iter_first() / isc_interface_iter_next().
  *
  * Returns:
- *     ISC_R_SUCCESS           Success.
+ *\li  #ISC_R_SUCCESS          Success.
  */
 
 isc_result_t
 isc_interfaceiter_next(isc_interfaceiter_t *iter);
-/*
- * Position the iterator on the next interface.
+/*!<
+ * \brief Position the iterator on the next interface.
  *
  * Requires:
- *     The iterator has been successfully positioned using
+ * \li The iterator has been successfully positioned using
  *     isc_interface_iter_first() / isc_interface_iter_next().
  *
  * Returns:
- *     ISC_R_SUCCESS           Success.
- *     ISC_R_NOMORE            There are no more interfaces.
+ *\li  #ISC_R_SUCCESS          Success.
+ *\li  #ISC_R_NOMORE           There are no more interfaces.
  */
 
 void
 isc_interfaceiter_destroy(isc_interfaceiter_t **iterp);
-/*
- * Destroy the iterator.
+/*!<
+ * \brief Destroy the iterator.
  */
 
 ISC_LANG_ENDDECLS
index 007de7c0dd372ec2b2d2a14effcee87cd14872a3..8054c9e18647110ea82c85bfdb8c143f5a7ec484 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ipv6.h,v 1.17.12.4 2004/03/09 05:21:09 marka Exp $ */
+/* $Id: ipv6.h,v 1.24 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_IPV6_H
 #define ISC_IPV6_H 1
 
-/*
+/*!
  * Also define LWRES_IPV6_H to keep it from being included if liblwres is
  * being used, or redefinition errors will occur.
  */
  ***** Module Info
  *****/
 
-/*
- * IPv6 definitions for systems which do not support IPv6.
+/*! \file isc/ipv6.h
+ * \brief IPv6 definitions for systems which do not support IPv6.
  *
- * MP:
+ * \li MP:
  *     No impact.
  *
- * Reliability:
+ * \li Reliability:
  *     No anticipated impact.
  *
- * Resources:
+ * \li Resources:
  *     N/A.
  *
- * Security:
+ * \li Security:
  *     No anticipated impact.
  *
- * Standards:
- *     RFC 2553.
+ * \li Standards:
+ *     RFC2553.
  */
 
 /***
 #include <isc/int.h>
 #include <isc/platform.h>
 
-/*
- * We probably don't need this on NTP
- */
-#ifdef ISC_ONLY_IPV6 
 /***
  *** Types.
  ***/
@@ -76,8 +72,8 @@ struct in6_addr {
 #define s6_addr16      _S6_un._S6_u16
 #define s6_addr32      _S6_un._S6_u32
 
-#define IN6ADDR_ANY_INIT       {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}
-#define IN6ADDR_LOOPBACK_INIT  {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}
+#define IN6ADDR_ANY_INIT       {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
+#define IN6ADDR_LOOPBACK_INIT  {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}}
 
 LIBISC_EXTERNAL_DATA extern const struct in6_addr in6addr_any;
 LIBISC_EXTERNAL_DATA extern const struct in6_addr in6addr_loopback;
@@ -99,17 +95,16 @@ struct sockaddr_in6 {
 #define SIN6_LEN 1
 #endif
 
-/*
+/*%
  * Unspecified
  */
-#ifndef IN6_IS_ADDR_UNSPECIFIED
 #define IN6_IS_ADDR_UNSPECIFIED(a)      \
         (((a)->s6_addr32[0] == 0) &&    \
          ((a)->s6_addr32[1] == 0) &&    \
          ((a)->s6_addr32[2] == 0) &&    \
          ((a)->s6_addr32[3] == 0))
-#endif
-/*
+
+/*%
  * Loopback
  */
 #define IN6_IS_ADDR_LOOPBACK(a)         \
@@ -118,7 +113,7 @@ struct sockaddr_in6 {
          ((a)->s6_addr32[2] == 0) &&    \
          ((a)->s6_addr32[3] == htonl(1)))
 
-/*
+/*%
  * IPv4 compatible
  */
 #define IN6_IS_ADDR_V4COMPAT(a)         \
@@ -128,7 +123,7 @@ struct sockaddr_in6 {
          ((a)->s6_addr32[3] != 0) &&    \
          ((a)->s6_addr32[3] != htonl(1)))
 
-/*
+/*%
  * Mapped
  */
 #define IN6_IS_ADDR_V4MAPPED(a)               \
@@ -136,14 +131,13 @@ struct sockaddr_in6 {
          ((a)->s6_addr32[1] == 0) &&          \
          ((a)->s6_addr32[2] == htonl(0x0000ffff)))
 
-/*
+/*%
  * Multicast
  */
-#ifndef IN6_IS_ADDR_MULTICAST
 #define IN6_IS_ADDR_MULTICAST(a)       \
        ((a)->s6_addr8[0] == 0xffU)
-#endif
-/*
+
+/*%
  * Unicast link / site local.
  */
 #define IN6_IS_ADDR_LINKLOCAL(a)       \
@@ -151,5 +145,4 @@ struct sockaddr_in6 {
 #define IN6_IS_ADDR_SITELOCAL(a)       \
        (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
 
-#endif /* ISC_ONLY_IPV6 */
 #endif /* ISC_IPV6_H */
diff --git a/lib/isc/include/isc/iterated_hash.h b/lib/isc/include/isc/iterated_hash.h
new file mode 100644 (file)
index 0000000..a8173f0
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: iterated_hash.h,v 1.3 2008/09/25 04:02:39 tbox Exp $ */
+
+#ifndef ISC_ITERATED_HASH_H
+#define ISC_ITERATED_HASH_H 1
+
+#include <isc/lang.h>
+#include <isc/sha1.h>
+
+/*
+ * The maximal hash length that can be encoded it a name
+ * using base32hex.  floor(255/8)*5
+ */
+#define NSEC3_MAX_HASH_LENGTH 155
+
+/*
+ * The maximum has that can be encoded in a single label using
+ * base32hex.  floor(63/8)*5
+ */
+#define NSEC3_MAX_LABEL_HASH 35
+
+ISC_LANG_BEGINDECLS
+
+int isc_iterated_hash(unsigned char out[NSEC3_MAX_HASH_LENGTH],
+                     unsigned int hashalg, int iterations,
+                     const unsigned char *salt, int saltlength,
+                     const unsigned char *in, int inlength);
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ITERATED_HASH_H */
index b3ba5908fe14539a8ad8de055a833ed53b28737a..8c608669b224e5e66440fe8dca4aeab1fccd761b 100644 (file)
@@ -1,25 +1,27 @@
 /*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: lang.h,v 1.6 2001/01/09 21:57:03 bwelling Exp $ */
+/* $Id: lang.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_LANG_H
 #define ISC_LANG_H 1
 
+/*! \file isc/lang.h */
+
 #ifdef __cplusplus
 #define ISC_LANG_BEGINDECLS    extern "C" {
 #define ISC_LANG_ENDDECLS      }
diff --git a/lib/isc/include/isc/lex.h b/lib/isc/include/isc/lex.h
new file mode 100644 (file)
index 0000000..8612150
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lex.h,v 1.37 2008/05/30 23:47:01 tbox Exp $ */
+
+#ifndef ISC_LEX_H
+#define ISC_LEX_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/lex.h
+ * \brief The "lex" module provides a lightweight tokenizer.  It can operate
+ * on files or buffers, and can handle "include".  It is designed for
+ * parsing of DNS master files and the BIND configuration file, but
+ * should be general enough to tokenize other things, e.g. HTTP.
+ *
+ * \li MP:
+ *     No synchronization is provided.  Clients must ensure exclusive
+ *     access.
+ *
+ * \li Reliability:
+ *     No anticipated impact.
+ *
+ * \li Resources:
+ *     TBS
+ *
+ * \li Security:
+ *     No anticipated impact.
+ *
+ * \li Standards:
+ *     None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/region.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Options
+ ***/
+
+/*@{*/
+/*!
+ * Various options for isc_lex_gettoken().
+ */
+
+#define ISC_LEXOPT_EOL                 0x01    /*%< Want end-of-line token. */
+#define ISC_LEXOPT_EOF                 0x02    /*%< Want end-of-file token. */
+#define ISC_LEXOPT_INITIALWS           0x04    /*%< Want initial whitespace. */
+#define ISC_LEXOPT_NUMBER              0x08    /*%< Recognize numbers. */
+#define ISC_LEXOPT_QSTRING             0x10    /*%< Recognize qstrings. */
+/*@}*/
+
+/*@{*/
+/*!
+ * The ISC_LEXOPT_DNSMULTILINE option handles the processing of '(' and ')' in
+ * the DNS master file format.  If this option is set, then the
+ * ISC_LEXOPT_INITIALWS and ISC_LEXOPT_EOL options will be ignored when
+ * the paren count is > 0.  To use this option, '(' and ')' must be special
+ * characters.
+ */
+#define ISC_LEXOPT_DNSMULTILINE                0x20    /*%< Handle '(' and ')'. */
+#define ISC_LEXOPT_NOMORE              0x40    /*%< Want "no more" token. */
+
+#define ISC_LEXOPT_CNUMBER             0x80    /*%< Recognize octal and hex. */
+#define ISC_LEXOPT_ESCAPE              0x100   /*%< Recognize escapes. */
+#define ISC_LEXOPT_QSTRINGMULTILINE    0x200   /*%< Allow multiline "" strings */
+#define ISC_LEXOPT_OCTAL               0x400   /*%< Expect a octal number. */
+/*@}*/
+/*@{*/
+/*!
+ * Various commenting styles, which may be changed at any time with
+ * isc_lex_setcomments().
+ */
+
+#define ISC_LEXCOMMENT_C               0x01
+#define ISC_LEXCOMMENT_CPLUSPLUS       0x02
+#define ISC_LEXCOMMENT_SHELL           0x04
+#define ISC_LEXCOMMENT_DNSMASTERFILE   0x08
+/*@}*/
+
+/***
+ *** Types
+ ***/
+
+/*! Lex */
+
+typedef char isc_lexspecials_t[256];
+
+/* Tokens */
+
+typedef enum {
+       isc_tokentype_unknown = 0,
+       isc_tokentype_string = 1,
+       isc_tokentype_number = 2,
+       isc_tokentype_qstring = 3,
+       isc_tokentype_eol = 4,
+       isc_tokentype_eof = 5,
+       isc_tokentype_initialws = 6,
+       isc_tokentype_special = 7,
+       isc_tokentype_nomore = 8
+} isc_tokentype_t;
+
+typedef union {
+       char                            as_char;
+       unsigned long                   as_ulong;
+       isc_region_t                    as_region;
+       isc_textregion_t                as_textregion;
+       void *                          as_pointer;
+} isc_tokenvalue_t;
+
+typedef struct isc_token {
+       isc_tokentype_t                 type;
+       isc_tokenvalue_t                value;
+} isc_token_t;
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp);
+/*%<
+ * Create a lexer.
+ *
+ * 'max_token' is a hint of the number of bytes in the largest token.
+ *
+ * Requires:
+ *\li  '*lexp' is a valid lexer.
+ *
+ *\li  max_token > 0.
+ *
+ * Ensures:
+ *\li  On success, *lexp is attached to the newly created lexer.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ */
+
+void
+isc_lex_destroy(isc_lex_t **lexp);
+/*%<
+ * Destroy the lexer.
+ *
+ * Requires:
+ *\li  '*lexp' is a valid lexer.
+ *
+ * Ensures:
+ *\li  *lexp == NULL
+ */
+
+unsigned int
+isc_lex_getcomments(isc_lex_t *lex);
+/*%<
+ * Return the current lexer commenting styles.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ * Returns:
+ *\li  The commenting sytles which are currently allowed.
+ */
+
+void
+isc_lex_setcomments(isc_lex_t *lex, unsigned int comments);
+/*%<
+ * Set allowed lexer commenting styles.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ *\li  'comments' has meaningful values.
+ */
+
+void
+isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials);
+/*%<
+ * Put the current list of specials into 'specials'.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ */
+
+void
+isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials);
+/*!<
+ * The characters in 'specials' are returned as tokens.  Along with
+ * whitespace, they delimit strings and numbers.
+ *
+ * Note:
+ *\li  Comment processing takes precedence over special character
+ *     recognition.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ */
+
+isc_result_t
+isc_lex_openfile(isc_lex_t *lex, const char *filename);
+/*%<
+ * Open 'filename' and make it the current input source for 'lex'.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ *\li  filename is a valid C string.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY                 Out of memory
+ *\li  #ISC_R_NOTFOUND                 File not found
+ *\li  #ISC_R_NOPERM                   No permission to open file
+ *\li  #ISC_R_FAILURE                  Couldn't open file, not sure why
+ *\li  #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_lex_openstream(isc_lex_t *lex, FILE *stream);
+/*%<
+ * Make 'stream' the current input source for 'lex'.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ *\li  'stream' is a valid C stream.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY                 Out of memory
+ */
+
+isc_result_t
+isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer);
+/*%<
+ * Make 'buffer' the current input source for 'lex'.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ *\li  'buffer' is a valid buffer.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY                 Out of memory
+ */
+
+isc_result_t
+isc_lex_close(isc_lex_t *lex);
+/*%<
+ * Close the most recently opened object (i.e. file or buffer).
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMORE                   No more input sources
+ */
+
+isc_result_t
+isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp);
+/*%<
+ * Get the next token.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ *\li  'lex' has an input source.
+ *
+ *\li  'options' contains valid options.
+ *
+ *\li  '*tokenp' is a valid pointer.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_UNEXPECTEDEND
+ *\li  #ISC_R_NOMEMORY
+ *
+ *     These two results are returned only if their corresponding lexer
+ *     options are not set.
+ *
+ *\li  #ISC_R_EOF                      End of input source
+ *\li  #ISC_R_NOMORE                   No more input sources
+ */
+
+isc_result_t
+isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
+                      isc_tokentype_t expect, isc_boolean_t eol);
+/*%<
+ * Get the next token from a DNS master file type stream.  This is a
+ * convenience function that sets appropriate options and handles quoted
+ * strings and end of line correctly for master files.  It also ungets
+ * unexpected tokens.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ *\li  'token' is a valid pointer
+ *
+ * Returns:
+ *
+ * \li any return code from isc_lex_gettoken().
+ */
+
+isc_result_t
+isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol);
+/*%<
+ * Get the next token from a DNS master file type stream.  This is a
+ * convenience function that sets appropriate options and handles end
+ * of line correctly for master files.  It also ungets unexpected tokens.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ *\li  'token' is a valid pointer
+ *
+ * Returns:
+ *
+ * \li any return code from isc_lex_gettoken().
+ */
+
+void
+isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp);
+/*%<
+ * Unget the current token.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ *\li  'lex' has an input source.
+ *
+ *\li  'tokenp' points to a valid token.
+ *
+ *\li  There is no ungotten token already.
+ */
+
+void
+isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r);
+/*%<
+ * Returns a region containing the text of the last token returned.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ *\li  'lex' has an input source.
+ *
+ *\li  'tokenp' points to a valid token.
+ *
+ *\li  A token has been gotten and not ungotten.
+ */
+
+char *
+isc_lex_getsourcename(isc_lex_t *lex);
+/*%<
+ * Return the input source name.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li source name or NULL if no current source.
+ *\li  result valid while current input source exists.
+ */
+
+
+unsigned long
+isc_lex_getsourceline(isc_lex_t *lex);
+/*%<
+ * Return the input source line number.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ * Returns:
+ *\li  Current line number or 0 if no current source.
+ */
+
+isc_result_t
+isc_lex_setsourcename(isc_lex_t *lex, const char *name);
+/*%<
+ * Assigns a new name to the input source.
+ *
+ * Requires:
+ *
+ * \li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ * \li #ISC_R_NOTFOUND - there are no sources.
+ */
+
+isc_boolean_t
+isc_lex_isfile(isc_lex_t *lex);
+/*%<
+ * Return whether the current input source is a file.
+ *
+ * Requires:
+ *\li  'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #ISC_TRUE if the current input is a file,
+ *\li  #ISC_FALSE otherwise.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LEX_H */
diff --git a/lib/isc/include/isc/lfsr.h b/lib/isc/include/isc/lfsr.h
new file mode 100644 (file)
index 0000000..d4d9707
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lfsr.h,v 1.17 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_LFSR_H
+#define ISC_LFSR_H 1
+
+/*! \file isc/lfsr.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+typedef struct isc_lfsr isc_lfsr_t;
+
+/*%
+ * This function is called when reseeding is needed.  It is allowed to
+ * modify any state in the LFSR in any way it sees fit OTHER THAN "bits".
+ *
+ * It MUST set "count" to a new value or the lfsr will never reseed again.
+ *
+ * Also, a reseed will never occur in the middle of an extraction.  This
+ * is purely an optimization, and is probably what one would want.
+ */
+typedef void (*isc_lfsrreseed_t)(isc_lfsr_t *, void *);
+
+/*%
+ * The members of this structure can be used by the application, but care
+ * needs to be taken to not change state once the lfsr is in operation.
+ */
+struct isc_lfsr {
+       isc_uint32_t            state;  /*%< previous state */
+       unsigned int            bits;   /*%< length */
+       isc_uint32_t            tap;    /*%< bit taps */
+       unsigned int            count;  /*%< reseed count (in BITS!) */
+       isc_lfsrreseed_t        reseed; /*%< reseed function */
+       void                   *arg;    /*%< reseed function argument */
+};
+
+ISC_LANG_BEGINDECLS
+
+
+void 
+isc_lfsr_init(isc_lfsr_t *lfsr, isc_uint32_t state, unsigned int bits,
+                  isc_uint32_t tap, unsigned int count,
+                  isc_lfsrreseed_t reseed, void *arg);
+/*%<
+ * Initialize an LFSR.
+ *
+ * Note:
+ *
+ *\li  Putting untrusted values into this function will cause the LFSR to
+ *     generate (perhaps) non-maximal length sequences.
+ *
+ * Requires:
+ *
+ *\li  lfsr != NULL
+ *
+ *\li  8 <= bits <= 32
+ *
+ *\li  tap != 0
+ */
+
+void 
+isc_lfsr_generate(isc_lfsr_t *lfsr, void *data, unsigned int count);
+/*%<
+ * Returns "count" bytes of data from the LFSR.
+ *
+ * Requires:
+ *
+ *\li  lfsr be valid.
+ *
+ *\li  data != NULL.
+ *
+ *\li  count > 0.
+ */
+
+void 
+isc_lfsr_skip(isc_lfsr_t *lfsr, unsigned int skip);
+/*%<
+ * Skip "skip" states.
+ *
+ * Requires:
+ *
+ *\li  lfsr be valid.
+ */
+
+isc_uint32_t 
+isc_lfsr_generate32(isc_lfsr_t *lfsr1, isc_lfsr_t *lfsr2);
+/*%<
+ * Given two LFSRs, use the current state from each to skip entries in the
+ * other.  The next states are then xor'd together and returned.
+ *
+ * WARNING:
+ *
+ *\li  This function is used only for very, very low security data, such
+ *     as DNS message IDs where it is desired to have an unpredictable
+ *     stream of bytes that are harder to predict than a simple flooding
+ *     attack.
+ *
+ * Notes:
+ *
+ *\li  Since the current state from each of the LFSRs is used to skip
+ *     state in the other, it is important that no state be leaked
+ *     from either LFSR.
+ *
+ * Requires:
+ *
+ *\li  lfsr1 and lfsr2 be valid.
+ *
+ *\li  1 <= skipbits <= 31
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_LFSR_H */
index 7feef43c5ebe55ef9c9b1288ffb4b3432a06233a..765cdfaa1996219908803133f47cd041eeb849d4 100644 (file)
@@ -1,25 +1,27 @@
 /*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: lib.h,v 1.7 2001/11/19 03:08:25 mayer Exp $ */
+/* $Id: lib.h,v 1.14 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_LIB_H
 #define ISC_LIB_H 1
 
+/*! \file isc/lib.h */
+
 #include <isc/types.h>
 #include <isc/lang.h>
 
@@ -29,8 +31,8 @@ LIBISC_EXTERNAL_DATA extern isc_msgcat_t *isc_msgcat;
 
 void
 isc_lib_initmsgcat(void);
-/*
- * Initialize the ISC library's message catalog, isc_msgcat, if it
+/*!<
+ * \brief Initialize the ISC library's message catalog, isc_msgcat, if it
  * has not already been initialized.
  */
 
index d0ae7a91a6f3f2046833a68c872a816ebc4c9be7..9338275c940a1f4df71f41de0078fa59285cee95 100644 (file)
@@ -1,21 +1,21 @@
 /*
- * Copyright (C) 1997-2001  Internet Software Consortium.
+ * Copyright (C) 2004, 2006, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: list.h,v 1.19 2002/05/09 07:09:30 marka Exp $ */
+/* $Id: list.h,v 1.24 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_LIST_H
 #define ISC_LIST_H 1
        do { \
                if ((elt)->link.next != NULL) \
                        (elt)->link.next->link.prev = (elt)->link.prev; \
-               else \
+               else { \
+                       ISC_INSIST((list).tail == (elt)); \
                        (list).tail = (elt)->link.prev; \
+               } \
                if ((elt)->link.prev != NULL) \
                        (elt)->link.prev->link.next = (elt)->link.next; \
-               else \
+               else { \
+                       ISC_INSIST((list).head == (elt)); \
                        (list).head = (elt)->link.next; \
+               } \
                (elt)->link.prev = (type *)(-1); \
                (elt)->link.next = (type *)(-1); \
        } while (0)
index c3817758faeeef5fa8d042e1fc83adf3d068070e..c9ba8082e52c38eb31e07120aaf871f9c67d3326 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: log.h,v 1.47.18.3 2005/04/29 00:16:58 marka Exp $ */
+/* $Id: log.h,v 1.54.332.5 2009/02/16 02:04:05 marka Exp $ */
 
 #ifndef ISC_LOG_H
 #define ISC_LOG_H 1
 
-/*! \file */
+/*! \file isc/log.h */
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -86,7 +86,7 @@
 /*@}*/
 
 /*!
- * \brief Used to name the categories used by a library.  
+ * \brief Used to name the categories used by a library.
  *
  * An array of isc_logcategory
  * structures names each category, and the id value is initialized by calling
@@ -107,13 +107,13 @@ struct isc_logmodule {
 
 /*%
  * The isc_logfile structure is initialized as part of an isc_logdestination
- * before calling isc_log_createchannel().  
+ * before calling isc_log_createchannel().
  *
  * When defining an #ISC_LOG_TOFILE
  * channel the name, versions and maximum_size should be set before calling
  * isc_log_createchannel().  To define an #ISC_LOG_TOFILEDESC channel set only
  * the stream before the call.
- * 
+ *
  * Setting maximum_size to zero implies no maximum.
  */
 typedef struct isc_logfile {
@@ -166,6 +166,7 @@ LIBISC_EXTERNAL_DATA extern isc_logmodule_t isc_modules[];
 #define ISC_LOGMODULE_TIME (&isc_modules[1])
 #define ISC_LOGMODULE_INTERFACE (&isc_modules[2])
 #define ISC_LOGMODULE_TIMER (&isc_modules[3])
+#define ISC_LOGMODULE_FILE (&isc_modules[4])
 
 ISC_LANG_BEGINDECLS
 
@@ -477,7 +478,7 @@ isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
  *     number of named channels.)  When multiple channels of the same
  *     name are defined, the most recent definition is found.
  *
- *\li  Specifing a very large number of channels for a category will have
+ *\li  Specifying a very large number of channels for a category will have
  *     a moderate impact on performance in isc_log_write(), as each
  *     call looks up the category for the start of a linked list, which
  *     it follows all the way to the end to find matching modules.  The
@@ -527,7 +528,7 @@ isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
  */
 
 /* Attention: next four comments PRECEED code */
-/*! 
+/*!
  *   \brief
  * Write a message to the log channels.
  *
@@ -546,7 +547,7 @@ isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
  *\li  lctx is a valid logging context.
  *
  *\li  The category and module arguments must have ids that are in the
- *     range of known ids, as estabished by isc_log_registercategories()
+ *     range of known ids, as established by isc_log_registercategories()
  *     and isc_log_registermodules().
  *
  *\li  level != #ISC_LOG_DYNAMIC.  ISC_LOG_DYNAMIC is used only to define
@@ -585,7 +586,7 @@ ISC_FORMAT_PRINTF(5, 6);
  *\li  lctx is a valid logging context.
  *
  *\li  The category and module arguments must have ids that are in the
- *     range of known ids, as estabished by isc_log_registercategories()
+ *     range of known ids, as established by isc_log_registercategories()
  *     and isc_log_registermodules().
  *
  *\li  level != #ISC_LOG_DYNAMIC.  ISC_LOG_DYNAMIC is used only to define
@@ -633,8 +634,8 @@ isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
 ISC_FORMAT_PRINTF(5, 0);
 
 /*%
- * These are four internationalized versions of the the isc_log_[v]write[1]
- * functions.  
+ * These are four internationalized versions of the isc_log_[v]write[1]
+ * functions.
  *
  * The only difference is that they take arguments for a message
  * catalog, message set, and message number, all immediately preceding the
@@ -824,7 +825,7 @@ isc_log_opensyslog(const char *tag, int options, int facility);
  *                     declared facility.
  * \endcode
  *
- *\li  Zero effort has been made (yet) to accomodate systems with openlog()
+ *\li  Zero effort has been made (yet) to accommodate systems with openlog()
  *     that only takes two arguments, or to identify valid syslog
  *     facilities or options for any given architecture.
  *
index ff3df24bdfc81ccef3ffc08995c1ec1591b347e6..073de90dcc9257e1fd35be2b6179c54f04f5ccfc 100644 (file)
@@ -1,34 +1,35 @@
 /*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: magic.h,v 1.11 2001/01/09 21:57:10 bwelling Exp $ */
+/* $Id: magic.h,v 1.18 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_MAGIC_H
 #define ISC_MAGIC_H 1
 
+/*! \file isc/magic.h */
+
 typedef struct {
        unsigned int magic;
 } isc__magic_t;
 
 
-/*
+/*%
  * To use this macro the magic number MUST be the first thing in the
  * structure, and MUST be of type "unsigned int".
- *
  * The intent of this is to allow magic numbers to be checked even though
  * the object is otherwise opaque.
  */
index 7881e18ec378c78c67c4ed3f11af12293c4362f2..480a934078ed9f0d5f660e1a3c6f7672c59daeaf 100644 (file)
 /*
- * short-circuited NTP-local imitation of isc/mem.h
- */
-
-/*
+ * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1997-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: mem.h,v 1.58 2001/09/07 00:51:51 marka Exp $ */
+/* $Id: mem.h,v 1.78.120.3 2009/02/11 03:07:01 jinmei Exp $ */
 
 #ifndef ISC_MEM_H
 #define ISC_MEM_H 1
 
-#include <stdlib.h>
+/*! \file isc/mem.h */
+
 #include <stdio.h>
 
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+#include <isc/xml.h>
+
+ISC_LANG_BEGINDECLS
+
+#define ISC_MEM_LOWATER 0
+#define ISC_MEM_HIWATER 1
+typedef void (*isc_mem_water_t)(void *, int);
+
+typedef void * (*isc_memalloc_t)(void *, size_t);
+typedef void (*isc_memfree_t)(void *, void *);
+
+/*%
+ * Define ISC_MEM_DEBUG=1 to make all functions that free memory
+ * set the pointer being freed to NULL after being freed.
+ * This is the default; set ISC_MEM_DEBUG=0 to disable it.
+ */
+#ifndef ISC_MEM_DEBUG
+#define ISC_MEM_DEBUG 1
+#endif
+
+/*%
+ * Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory
+ * allocation and freeing by file and line number.
+ */
+#ifndef ISC_MEM_TRACKLINES
+#define ISC_MEM_TRACKLINES 1
+#endif
+
+/*%
+ * Define ISC_MEM_CHECKOVERRUN=1 to turn on checks for using memory outside
+ * the requested space.  This will increase the size of each allocation.
+ */
+#ifndef ISC_MEM_CHECKOVERRUN
+#define ISC_MEM_CHECKOVERRUN 1
+#endif
+
+/*%
+ * Define ISC_MEM_FILL=1 to fill each block of memory returned to the system
+ * with the byte string '0xbe'.  This helps track down uninitialized pointers
+ * and the like.  On freeing memory, the space is filled with '0xde' for
+ * the same reasons.
+ */
+#ifndef ISC_MEM_FILL
+#define ISC_MEM_FILL 1
+#endif
+
+/*%
+ * Define ISC_MEMPOOL_NAMES=1 to make memory pools store a symbolic
+ * name so that the leaking pool can be more readily identified in
+ * case of a memory leak.
+ */
+#ifndef ISC_MEMPOOL_NAMES
+#define ISC_MEMPOOL_NAMES 1
+#endif
+
+LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_debugging;
+/*@{*/
+#define ISC_MEM_DEBUGTRACE             0x00000001U
+#define ISC_MEM_DEBUGRECORD            0x00000002U
+#define ISC_MEM_DEBUGUSAGE             0x00000004U
+#define ISC_MEM_DEBUGSIZE              0x00000008U
+#define ISC_MEM_DEBUGCTX               0x00000010U
+#define ISC_MEM_DEBUGALL               0x0000001FU
+/*!<
+ * The variable isc_mem_debugging holds a set of flags for
+ * turning certain memory debugging options on or off at
+ * runtime.  It is initialized to the value ISC_MEM_DEGBUGGING,
+ * which is 0 by default but may be overridden at compile time.
+ * The following flags can be specified:
+ *
+ * \li #ISC_MEM_DEBUGTRACE
+ *     Log each allocation and free to isc_lctx.
+ *
+ * \li #ISC_MEM_DEBUGRECORD
+ *     Remember each allocation, and match them up on free.
+ *     Crash if a free doesn't match an allocation.
+ *
+ * \li #ISC_MEM_DEBUGUSAGE
+ *     If a hi_water mark is set, print the maximum inuse memory
+ *     every time it is raised once it exceeds the hi_water mark.
+ *
+ * \li #ISC_MEM_DEBUGSIZE
+ *     Check the size argument being passed to isc_mem_put() matches
+ *     that passed to isc_mem_get().
+ *
+ * \li #ISC_MEM_DEBUGCTX
+ *     Check the mctx argument being passed to isc_mem_put() matches
+ *     that passed to isc_mem_get().
+ */
+/*@}*/
+
+#if ISC_MEM_TRACKLINES
+#define _ISC_MEM_FILELINE      , __FILE__, __LINE__
+#define _ISC_MEM_FLARG         , const char *, int
+#else
+#define _ISC_MEM_FILELINE
+#define _ISC_MEM_FLARG
+#endif
+
+/*!
+ * Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc()
+ * implementation in preference to the system one.  The internal malloc()
+ * is very space-efficient, and quite fast on uniprocessor systems.  It
+ * performs poorly on multiprocessor machines.
+ * JT: we can overcome the performance issue on multiprocessor machines
+ * by carefully separating memory contexts.
+ */
+
+#ifndef ISC_MEM_USE_INTERNAL_MALLOC
+#define ISC_MEM_USE_INTERNAL_MALLOC 1
+#endif
+
+/*
+ * Flags for isc_mem_create2()calls.
+ */
+#define ISC_MEMFLAG_NOLOCK     0x00000001       /* no lock is necessary */
+#define ISC_MEMFLAG_INTERNAL   0x00000002       /* use internal malloc */
+#if ISC_MEM_USE_INTERNAL_MALLOC
+#define ISC_MEMFLAG_DEFAULT    ISC_MEMFLAG_INTERNAL
+#else
+#define ISC_MEMFLAG_DEFAULT    0
+#endif
+
+
+#define isc_mem_get(c, s)      isc__mem_get((c), (s) _ISC_MEM_FILELINE)
+#define isc_mem_allocate(c, s) isc__mem_allocate((c), (s) _ISC_MEM_FILELINE)
+#define isc_mem_reallocate(c, p, s) isc__mem_reallocate((c), (p), (s) _ISC_MEM_FILELINE)
+#define isc_mem_strdup(c, p)   isc__mem_strdup((c), (p) _ISC_MEM_FILELINE)
+#define isc_mempool_get(c)     isc__mempool_get((c) _ISC_MEM_FILELINE)
+
+/*%
+ * isc_mem_putanddetach() is a convenience function for use where you
+ * have a structure with an attached memory context.
+ *
+ * Given:
+ *
+ * \code
+ * struct {
+ *     ...
+ *     isc_mem_t *mctx;
+ *     ...
+ * } *ptr;
+ *
+ * isc_mem_t *mctx;
+ *
+ * isc_mem_putanddetach(&ptr->mctx, ptr, sizeof(*ptr));
+ * \endcode
+ *
+ * is the equivalent of:
+ *
+ * \code
+ * mctx = NULL;
+ * isc_mem_attach(ptr->mctx, &mctx);
+ * isc_mem_detach(&ptr->mctx);
+ * isc_mem_put(mctx, ptr, sizeof(*ptr));
+ * isc_mem_detach(&mctx);
+ * \endcode
+ */
+
+#if ISC_MEM_DEBUG
+#define isc_mem_put(c, p, s) \
+       do { \
+               isc__mem_put((c), (p), (s) _ISC_MEM_FILELINE); \
+               (p) = NULL; \
+       } while (0)
+#define isc_mem_putanddetach(c, p, s) \
+       do { \
+               isc__mem_putanddetach((c), (p), (s) _ISC_MEM_FILELINE); \
+               (p) = NULL; \
+       } while (0)
+#define isc_mem_free(c, p) \
+       do { \
+               isc__mem_free((c), (p) _ISC_MEM_FILELINE); \
+               (p) = NULL; \
+       } while (0)
+#define isc_mempool_put(c, p) \
+       do { \
+               isc__mempool_put((c), (p) _ISC_MEM_FILELINE); \
+               (p) = NULL; \
+       } while (0)
+#else
+#define isc_mem_put(c, p, s)   isc__mem_put((c), (p), (s) _ISC_MEM_FILELINE)
+#define isc_mem_putanddetach(c, p, s) \
+       isc__mem_putanddetach((c), (p), (s) _ISC_MEM_FILELINE)
+#define isc_mem_free(c, p)     isc__mem_free((c), (p) _ISC_MEM_FILELINE)
+#define isc_mempool_put(c, p)  isc__mempool_put((c), (p) _ISC_MEM_FILELINE)
+#endif
+
+/*@{*/
+isc_result_t
+isc_mem_create(size_t max_size, size_t target_size,
+              isc_mem_t **mctxp);
+
+isc_result_t
+isc_mem_create2(size_t max_size, size_t target_size,
+               isc_mem_t **mctxp, unsigned int flags);
+
+isc_result_t
+isc_mem_createx(size_t max_size, size_t target_size,
+               isc_memalloc_t memalloc, isc_memfree_t memfree,
+               void *arg, isc_mem_t **mctxp);
+
+isc_result_t
+isc_mem_createx2(size_t max_size, size_t target_size,
+                isc_memalloc_t memalloc, isc_memfree_t memfree,
+                void *arg, isc_mem_t **mctxp, unsigned int flags);
+
+/*!<
+ * \brief Create a memory context.
+ *
+ * 'max_size' and 'target_size' are tuning parameters.  When
+ * ISC_MEMFLAG_INTERNAL is set, allocations smaller than 'max_size'
+ * will be satisfied by getting blocks of size 'target_size' from the
+ * system allocator and breaking them up into pieces; larger allocations
+ * will use the system allocator directly. If 'max_size' and/or
+ * 'target_size' are zero, default values will be * used.  When
+ * ISC_MEMFLAG_INTERNAL is not set, 'target_size' is ignored.
+ *
+ * 'max_size' is also used to size the statistics arrays and the array
+ * used to record active memory when ISC_MEM_DEBUGRECORD is set.  Settin
+ * 'max_size' too low can have detrimental effects on performance.
+ *
+ * A memory context created using isc_mem_createx() will obtain
+ * memory from the system by calling 'memalloc' and 'memfree',
+ * passing them the argument 'arg'.  A memory context created
+ * using isc_mem_create() will use the standard library malloc()
+ * and free().
+ *
+ * If ISC_MEMFLAG_NOLOCK is set in 'flags', the corresponding memory context
+ * will be accessed without locking.  The user who creates the context must
+ * ensure there be no race.  Since this can be a source of bug, it is generally
+ * inadvisable to use this flag unless the user is very sure about the race
+ * condition and the access to the object is highly performance sensitive.
+ *
+ * Requires:
+ * mctxp != NULL && *mctxp == NULL */
+/*@}*/
+
+/*@{*/
+void
+isc_mem_attach(isc_mem_t *, isc_mem_t **);
+void
+isc_mem_detach(isc_mem_t **);
+/*!<
+ * \brief Attach to / detach from a memory context.
+ *
+ * This is intended for applications that use multiple memory contexts
+ * in such a way that it is not obvious when the last allocations from
+ * a given context has been freed and destroying the context is safe.
+ *
+ * Most applications do not need to call these functions as they can
+ * simply create a single memory context at the beginning of main()
+ * and destroy it at the end of main(), thereby guaranteeing that it
+ * is not destroyed while there are outstanding allocations.
+ */
+/*@}*/
+
+void
+isc_mem_destroy(isc_mem_t **);
+/*%<
+ * Destroy a memory context.
+ */
+
+isc_result_t
+isc_mem_ondestroy(isc_mem_t *ctx,
+                 isc_task_t *task,
+                 isc_event_t **event);
+/*%<
+ * Request to be notified with an event when a memory context has
+ * been successfully destroyed.
+ */
+
+void
+isc_mem_stats(isc_mem_t *mctx, FILE *out);
+/*%<
+ * Print memory usage statistics for 'mctx' on the stream 'out'.
+ */
+
+void
+isc_mem_setdestroycheck(isc_mem_t *mctx,
+                       isc_boolean_t on);
+/*%<
+ * If 'on' is ISC_TRUE, 'mctx' will check for memory leaks when
+ * destroyed and abort the program if any are present.
+ */
+
+/*@{*/
+void
+isc_mem_setquota(isc_mem_t *, size_t);
+size_t
+isc_mem_getquota(isc_mem_t *);
+/*%<
+ * Set/get the memory quota of 'mctx'.  This is a hard limit
+ * on the amount of memory that may be allocated from mctx;
+ * if it is exceeded, allocations will fail.
+ */
+/*@}*/
+
+size_t
+isc_mem_inuse(isc_mem_t *mctx);
+/*%<
+ * Get an estimate of the number of memory in use in 'mctx', in bytes.
+ * This includes quantization overhead, but does not include memory
+ * allocated from the system but not yet used.
+ */
+
+void
+isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg,
+                size_t hiwater, size_t lowater);
+/*%<
+ * Set high and low water marks for this memory context.
+ *
+ * When the memory usage of 'mctx' exceeds 'hiwater',
+ * '(water)(water_arg, #ISC_MEM_HIWATER)' will be called.  'water' needs to
+ * call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the state
+ * change.  'water' may be called multiple times.
+ *
+ * When the usage drops below 'lowater', 'water' will again be called, this
+ * time with #ISC_MEM_LOWATER.  'water' need to calls isc_mem_waterack() with
+ * #ISC_MEM_LOWATER to acknowledge the change.
+ *
+ *     static void
+ *     water(void *arg, int mark) {
+ *             struct foo *foo = arg;
+ *
+ *             LOCK(&foo->marklock);
+ *             if (foo->mark != mark) {
+ *                     foo->mark = mark;
+ *                     ....
+ *                     isc_mem_waterack(foo->mctx, mark);
+ *             }
+ *             UNLOCK(&foo->marklock);
+ *     }
+ *
+ * If 'water' is NULL then 'water_arg', 'hi_water' and 'lo_water' are
+ * ignored and the state is reset.
+ *
+ * Requires:
+ *
+ *     'water' is not NULL.
+ *     hi_water >= lo_water
+ */
+
+void
+isc_mem_waterack(isc_mem_t *ctx, int mark);
+/*%<
+ * Called to acknowledge changes in signaled by calls to 'water'.
+ */
+
+void
+isc_mem_printactive(isc_mem_t *mctx, FILE *file);
+/*%<
+ * Print to 'file' all active memory in 'mctx'.
+ *
+ * Requires ISC_MEM_DEBUGRECORD to have been set.
+ */
+
+void
+isc_mem_printallactive(FILE *file);
+/*%<
+ * Print to 'file' all active memory in all contexts.
+ *
+ * Requires ISC_MEM_DEBUGRECORD to have been set.
+ */
+
+void
+isc_mem_checkdestroyed(FILE *file);
+/*%<
+ * Check that all memory contexts have been destroyed.
+ * Prints out those that have not been.
+ * Fatally fails if there are still active contexts.
+ */
+
+unsigned int
+isc_mem_references(isc_mem_t *ctx);
+/*%<
+ * Return the current reference count.
+ */
+
+void
+isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag);
+/*%<
+ * Name 'ctx'.
+ *
+ * Notes:
+ *
+ *\li  Only the first 15 characters of 'name' will be copied.
+ *
+ *\li  'tag' is for debugging purposes only.
+ *
+ * Requires:
+ *
+ *\li  'ctx' is a valid ctx.
+ */
+
+const char *
+isc_mem_getname(isc_mem_t *ctx);
+/*%<
+ * Get the name of 'ctx', as previously set using isc_mem_setname().
+ *
+ * Requires:
+ *\li  'ctx' is a valid ctx.
+ *
+ * Returns:
+ *\li  A non-NULL pointer to a null-terminated string.
+ *     If the ctx has not been named, the string is
+ *     empty.
+ */
+
+void *
+isc_mem_gettag(isc_mem_t *ctx);
+/*%<
+ * Get the tag value for  'task', as previously set using isc_mem_setname().
+ *
+ * Requires:
+ *\li  'ctx' is a valid ctx.
+ *
+ * Notes:
+ *\li  This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li  'ctx' is a valid task.
+ */
+
+#ifdef HAVE_LIBXML2
+void
+isc_mem_renderxml(xmlTextWriterPtr writer);
+/*%<
+ * Render all contexts' statistics and status in XML for writer.
+ */
+#endif /* HAVE_LIBXML2 */
+
+/*
+ * Memory pools
+ */
+
+isc_result_t
+isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
+/*%<
+ * Create a memory pool.
+ *
+ * Requires:
+ *\li  mctx is a valid memory context.
+ *\li  size > 0
+ *\li  mpctxp != NULL and *mpctxp == NULL
+ *
+ * Defaults:
+ *\li  maxalloc = UINT_MAX
+ *\li  freemax = 1
+ *\li  fillcount = 1
+ *
+ * Returns:
+ *\li  #ISC_R_NOMEMORY         -- not enough memory to create pool
+ *\li  #ISC_R_SUCCESS          -- all is well.
+ */
+
+void
+isc_mempool_destroy(isc_mempool_t **mpctxp);
+/*%<
+ * Destroy a memory pool.
+ *
+ * Requires:
+ *\li  mpctxp != NULL && *mpctxp is a valid pool.
+ *\li  The pool has no un"put" allocations outstanding
+ */
+
+void
+isc_mempool_setname(isc_mempool_t *mpctx, const char *name);
+/*%<
+ * Associate a name with a memory pool.  At most 15 characters may be used.
+ *
+ * Requires:
+ *\li  mpctx is a valid pool.
+ *\li  name != NULL;
+ */
+
+void
+isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
+/*%<
+ * Associate a lock with this memory pool.
+ *
+ * This lock is used when getting or putting items using this memory pool,
+ * and it is also used to set or get internal state via the isc_mempool_get*()
+ * and isc_mempool_set*() set of functions.
+ *
+ * Multiple pools can each share a single lock.  For instance, if "manager"
+ * type object contained pools for various sizes of events, and each of
+ * these pools used a common lock.  Note that this lock must NEVER be used
+ * by other than mempool routines once it is given to a pool, since that can
+ * easily cause double locking.
+ *
+ * Requires:
+ *
+ *\li  mpctpx is a valid pool.
+ *
+ *\li  lock != NULL.
+ *
+ *\li  No previous lock is assigned to this pool.
+ *
+ *\li  The lock is initialized before calling this function via the normal
+ *     means of doing that.
+ */
+
+/*
+ * The following functions get/set various parameters.  Note that due to
+ * the unlocked nature of pools these are potentially random values unless
+ * the imposed externally provided locking protocols are followed.
+ *
+ * Also note that the quota limits will not always take immediate effect.
+ * For instance, setting "maxalloc" to a number smaller than the currently
+ * allocated count is permitted.  New allocations will be refused until
+ * the count drops below this threshold.
+ *
+ * All functions require (in addition to other requirements):
+ *     mpctx is a valid memory pool
+ */
+
+unsigned int
+isc_mempool_getfreemax(isc_mempool_t *mpctx);
+/*%<
+ * Returns the maximum allowed size of the free list.
+ */
+
+void
+isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
+/*%<
+ * Sets the maximum allowed size of the free list.
+ */
+
+unsigned int
+isc_mempool_getfreecount(isc_mempool_t *mpctx);
+/*%<
+ * Returns current size of the free list.
+ */
+
+unsigned int
+isc_mempool_getmaxalloc(isc_mempool_t *mpctx);
+/*!<
+ * Returns the maximum allowed number of allocations.
+ */
+
+void
+isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
+/*%<
+ * Sets the maximum allowed number of allocations.
+ *
+ * Additional requirements:
+ *\li  limit > 0
+ */
+
+unsigned int
+isc_mempool_getallocated(isc_mempool_t *mpctx);
+/*%<
+ * Returns the number of items allocated from this pool.
+ */
+
+unsigned int
+isc_mempool_getfillcount(isc_mempool_t *mpctx);
+/*%<
+ * Returns the number of items allocated as a block from the parent memory
+ * context when the free list is empty.
+ */
+
+void
+isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
+/*%<
+ * Sets the fillcount.
+ *
+ * Additional requirements:
+ *\li  limit > 0
+ */
+
+
+/*
+ * Pseudo-private functions for use via macros.  Do not call directly.
+ */
+void *
+isc__mem_get(isc_mem_t *, size_t _ISC_MEM_FLARG);
+void
+isc__mem_putanddetach(isc_mem_t **, void *,
+                                     size_t _ISC_MEM_FLARG);
+void
+isc__mem_put(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
+void *
+isc__mem_allocate(isc_mem_t *, size_t _ISC_MEM_FLARG);
+void *
+isc__mem_reallocate(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
+void
+isc__mem_free(isc_mem_t *, void * _ISC_MEM_FLARG);
+char *
+isc__mem_strdup(isc_mem_t *, const char *_ISC_MEM_FLARG);
+void *
+isc__mempool_get(isc_mempool_t * _ISC_MEM_FLARG);
+void
+isc__mempool_put(isc_mempool_t *, void * _ISC_MEM_FLARG);
 
-#define        isc_mem_get(c, cnt)             malloc((cnt) ? (cnt) : 1)
-#define        isc_mem_put(c, mem, cnt)        free(mem)
-#define isc_mem_free(c, mem)           free(mem)
-#define isc_mem_strdup(c, str)         strdup(str)
+ISC_LANG_ENDDECLS
 
 #endif /* ISC_MEM_H */
index d2bf1e1622d9036f398208af607586e74421d7b5..fe3d336825f0e261ce255ef8f3451c633beb5ce8 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: msgcat.h,v 1.8 2001/01/09 21:57:13 bwelling Exp $ */
+/* $Id: msgcat.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_MSGCAT_H
 #define ISC_MSGCAT_H 1
  ***** Module Info
  *****/
 
-/*
- * ISC Message Catalog
- *
- * Message catalogs aid internationalization of applications by allowing
+/*! \file isc/msgcat.h
+ * \brief The ISC Message Catalog
+ * aids internationalization of applications by allowing
  * messages to be retrieved from locale-specific files instead of
  * hardwiring them into the application.  This allows translations of
  * messages appropriate to the locale to be supplied without recompiling
  * the application.
  *
  * Notes:
- *     It's very important that message catalogs work, even if only the
+ *\li  It's very important that message catalogs work, even if only the
  *     default_text can be used.
  *
  * MP:
- *     The caller must ensure appropriate synchronization of
+ *\li  The caller must ensure appropriate synchronization of
  *     isc_msgcat_open() and isc_msgcat_close().  isc_msgcat_get()
  *     ensures appropriate synchronization.
  *
  * Reliability:
- *     No anticipated impact.
+ *\li  No anticipated impact.
  *
  * Resources:
- *     <TBS>
+ *\li  TBS
  *
- * Security:
+ * \li Security:
  *     No anticipated impact.
  *
- * Standards:
+ * \li Standards:
  *     None.
  */
 
@@ -70,61 +69,61 @@ ISC_LANG_BEGINDECLS
 
 void
 isc_msgcat_open(const char *name, isc_msgcat_t **msgcatp);
-/*
+/*%<
  * Open a message catalog.
  *
  * Notes:
  *
- *     If memory cannot be allocated or other failures occur, *msgcatp
+ *\li  If memory cannot be allocated or other failures occur, *msgcatp
  *     will be set to NULL.  If a NULL msgcat is given to isc_msgcat_get(),
  *     the default_text will be returned, ensuring that some message text
  *     will be available, no matter what's going wrong.
  *
  * Requires:
  *
- *     'name' is a valid string.
+ *\li  'name' is a valid string.
  *
- *     msgcatp != NULL && *msgcatp == NULL
+ *\li  msgcatp != NULL && *msgcatp == NULL
  */
 
 void
 isc_msgcat_close(isc_msgcat_t **msgcatp);
-/*
+/*%<
  * Close a message catalog.
  *
  * Notes:
  *
- *     Any string pointers returned by prior calls to isc_msgcat_get() are
+ *\li  Any string pointers returned by prior calls to isc_msgcat_get() are
  *     invalid after isc_msgcat_close() has been called and must not be
  *     used.
  *
  * Requires:
  *
- *     *msgcatp is a valid message catalog or is NULL.
+ *\li  *msgcatp is a valid message catalog or is NULL.
  *
  * Ensures:
  *
- *     All resources associated with the message catalog are released.
+ *\li  All resources associated with the message catalog are released.
  *
- *     *msgcatp == NULL
+ *\li  *msgcatp == NULL
  */
 
 const char *
 isc_msgcat_get(isc_msgcat_t *msgcat, int set, int message,
               const char *default_text);
-/*
+/*%<
  * Get message 'message' from message set 'set' in 'msgcat'.  If it
  * is not available, use 'default_text'.
  *
  * Requires:
  *
- *     'msgcat' is a valid message catalog or is NULL.
+ *\li  'msgcat' is a valid message catalog or is NULL.
  *
- *     set > 0
+ *\li  set > 0
  *
- *     message > 0
+ *\li  message > 0
  *
- *     'default_text' is a valid string.
+ *\li  'default_text' is a valid string.
  */
 
 ISC_LANG_ENDDECLS
index 967005bf35317fb231ada9a8d02ae9d2aef5c333..d8f2787a28a4ebdfd15d05546604bb58340456a2 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2000-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: msgs.h,v 1.5.2.2.8.3 2004/03/06 08:14:44 marka Exp $ */
+/* $Id: msgs.h,v 1.17 2008/08/08 06:28:59 tbox Exp $ */
 
 #ifndef ISC_MSGS_H
 #define ISC_MSGS_H 1
 
+/*! \file isc/msgs.h */
+
 #include <isc/lib.h>           /* Provide isc_msgcat global variable. */
 #include <isc/msgcat.h>                /* Provide isc_msgcat_*() functions. */
 
-/*
- * Message sets, named per source file, excepting "GENERAL".
+/*@{*/
+/*!
+ * \brief Message sets, named per source file, excepting "GENERAL".
+ *
  * IMPORTANT: The original list is alphabetical, but any new sets must
  * be added to the end.
  */
 #define ISC_MSGSET_TIMER       19
 #define ISC_MSGSET_UTIL                20
 #define ISC_MSGSET_IFITERGETIFADDRS 21
+/*@}*/
 
-/*
- * Message numbers.  They are only required to be unique per message set,
+/*@{*/
+/*!
+ * Message numbers
+ * are only required to be unique per message set,
  * but are unique throughout the entire catalog to not be as confusing when
  * debugging.
  *
  * The initial numbering was done by multiply by 100 the set number the
  * message appears in then adding the incremental message number.
  */
-#define ISC_MSG_FAILED         101 /* "failed" */
-#define ISC_MSG_SUCCEEDED      102 /* Compatible with "failed" */
-#define ISC_MSG_SUCCESS                103 /* More usual way to say "success" */
-#define ISC_MSG_STARTING       104 /* As in "daemon: starting" */
-#define ISC_MSG_STOPING                105 /* As in "daemon: stopping" */
-#define ISC_MSG_ENTERING       106 /* As in "some_subr: entering" */
-#define ISC_MSG_EXITING                107 /* As in "some_subr: exiting" */
-#define ISC_MSG_CALLING                108 /* As in "calling some_subr()" */
-#define ISC_MSG_RETURNED       109 /* As in "some_subr: returned <foo>" */
-#define ISC_MSG_FATALERROR     110 /* "fatal error" */
-#define ISC_MSG_SHUTTINGDOWN   111 /* "shutting down" */
-#define ISC_MSG_RUNNING                112 /* "running" */
-#define ISC_MSG_WAIT           113 /* "wait" */
-#define ISC_MSG_WAITUNTIL      114 /* "waituntil" */
-
-#define ISC_MSG_SIGNALSETUP    201 /* "handle_signal() %d setup: %s" */
-
-#define ISC_MSG_ILLEGALOPT     301 /* "illegal option" */
-#define ISC_MSG_OPTNEEDARG     302 /* "option requires an argument" */
-
-#define ISC_MSG_ENTROPYSTATS   401 /* "Entropy pool %p:  refcnt %u ..." */
-
-#define ISC_MSG_MAKESCANSOCKET 501 /* "making interface scan socket: %s" */
-#define ISC_MSG_GETIFCONFIG    502 /* "get interface configuration: %s" */
-#define ISC_MSG_BUFFERMAX      503 /* "... maximum buffer size exceeded" */
-#define ISC_MSG_GETDESTADDR    504 /* "%s: getting destination address: %s" */
-#define ISC_MSG_GETNETMASK     505 /* "%s: getting netmask: %s" */
-
-#define ISC_MSG_GETIFLISTSIZE  601 /* "getting interface list size: ..." */
-#define ISC_MSG_GETIFLIST      602 /* "getting interface list: ..." */
-#define ISC_MSG_UNEXPECTEDTYPE 603 /* "... unexpected ... message type" */
-
-#define ISC_MSG_UNEXPECTEDSTATE        701 /* "Unexpected state %d" */
-
-#define ISC_MSG_BADTIME                801 /* "Bad 00 99:99:99.999 " */
-#define ISC_MSG_LEVEL          802 /* "level %d: " */
-
-#define ISC_MSG_ADDTRACE       901 /* "add %p size %u " */
-#define ISC_MSG_DELTRACE       902 /* "del %p size %u " */
-#define ISC_MSG_POOLSTATS      903 /* "[Pool statistics]\n" */
-#define ISC_MSG_POOLNAME       904 /* "name" */
-#define ISC_MSG_POOLSIZE       905 /* "size" */
-#define ISC_MSG_POOLMAXALLOC   906 /* "maxalloc" */
-#define ISC_MSG_POOLALLOCATED  907 /* "allocated" */
-#define ISC_MSG_POOLFREECOUNT  908 /* "freecount" */
-#define ISC_MSG_POOLFREEMAX    909 /* "freemax" */
-#define ISC_MSG_POOLFILLCOUNT  910 /* "fillcount" */
-#define ISC_MSG_POOLGETS       911 /* "gets" */
-#define ISC_MSG_DUMPALLOC      912 /* "DUMP OF ALL OUTSTANDING MEMORY ..." */
-#define ISC_MSG_NONE           913 /* "\tNone.\n" */
-#define ISC_MSG_PTRFILELINE    914 /* "\tptr %p file %s line %u\n" */
-
-#define ISC_MSG_UNKNOWNADDR    1001 /* "<unknown address, family %u>" */
-
-#define ISC_MSG_NOLONGDBL      1104 /* "long doubles are not supported" */
-
-#define ISC_MSG_PRINTLOCK      1201 /* "rwlock %p thread %lu ..." */
-#define ISC_MSG_READ          1202 /* "read" */
-#define ISC_MSG_WRITE         1203 /* "write" */
-#define ISC_MSG_READING               1204 /* "reading" */
-#define ISC_MSG_WRITING               1205 /* "writing" */
-#define ISC_MSG_PRELOCK               1206 /* "prelock" */
-#define ISC_MSG_POSTLOCK       1207 /* "postlock" */
-#define ISC_MSG_PREUNLOCK      1208 /* "preunlock" */
-#define ISC_MSG_POSTUNLOCK     1209 /* "postunlock" */
-
-#define ISC_MSG_UNKNOWNFAMILY  1301 /* "unknown address family: %d" */
-
-#define ISC_MSG_WRITEFAILED    1401 /* "write() failed during watcher ..." */
-#define ISC_MSG_READFAILED     1402 /* "read() failed during watcher ... " */
-#define ISC_MSG_PROCESSCMSG    1403 /* "processing cmsg %p" */
-#define ISC_MSG_IFRECEIVED     1404 /* "interface received on ifindex %u" */
-#define ISC_MSG_SENDTODATA     1405 /* "sendto pktinfo data, ifindex %u" */
-#define ISC_MSG_DOIORECV       1406 /* "doio_recv: recvmsg(%d) %d bytes ..." */
-#define ISC_MSG_PKTRECV               1407 /* "packet received correctly" */
-#define ISC_MSG_DESTROYING     1408 /* "destroying" */
-#define ISC_MSG_CREATED               1409 /* "created" */
-#define ISC_MSG_ACCEPTLOCK     1410 /* "internal_accept called, locked ..." */
-#define ISC_MSG_ACCEPTEDCXN    1411 /* "accepted connection, new socket %p" */
-#define ISC_MSG_INTERNALRECV   1412 /* "internal_recv: task %p got event %p" */
-#define ISC_MSG_INTERNALSEND   1413 /* "internal_send: task %p got event %p" */
-#define ISC_MSG_WATCHERMSG     1414 /* "watcher got message %d" */
-#define ISC_MSG_SOCKETSREMAIN  1415 /* "sockets exist" */
-#define ISC_MSG_PKTINFOPROVIDED        1416 /* "pktinfo structure provided, ..." */
-#define ISC_MSG_BOUND         1417 /* "bound" */
-#define ISC_MSG_ACCEPTRETURNED 1418 /* accept() returned %d/%s */
-#define ISC_MSG_TOOMANYFDS     1419 /* %s: too many open file descriptors */
-#define ISC_MSG_ZEROPORT       1420 /* dropping source port zero packet */
-#define ISC_MSG_FILTER        1420 /* setsockopt(SO_ACCEPTFILTER): %s */
-
-#define ISC_MSG_AWAKE         1502 /* "awake" */
-#define ISC_MSG_WORKING               1503 /* "working" */
-#define ISC_MSG_EXECUTE               1504 /* "execute action" */
-#define ISC_MSG_EMPTY         1505 /* "empty" */
-#define ISC_MSG_DONE          1506 /* "done" */
-#define ISC_MSG_QUANTUM               1507 /* "quantum" */
-
-#define ISC_MSG_SCHEDULE       1601 /* "schedule" */
-#define ISC_MSG_SIGNALSCHED    1602 /* "signal (schedule)" */
-#define ISC_MSG_SIGNALDESCHED  1603 /* "signal (deschedule)" */
-#define ISC_MSG_SIGNALDESTROY  1604 /* "signal (destroy)" */
-#define ISC_MSG_IDLERESCHED    1605 /* "idle reschedule" */
-#define ISC_MSG_EVENTNOTALLOC  1606 /* "couldn't allocate event" */
-#define ISC_MSG_SCHEDFAIL      1607 /* "couldn't schedule timer: %u" */
-#define ISC_MSG_POSTING               1608 /* "posting" */
-#define ISC_MSG_WAKEUP        1609 /* "wakeup" */
-
-#define ISC_MSG_LOCK          1701 /* "LOCK" */
-#define ISC_MSG_LOCKING               1702 /* "LOCKING" */
-#define ISC_MSG_LOCKED        1703 /* "LOCKED" */
-#define ISC_MSG_UNLOCKED       1704 /* "UNLOCKED" */
-#define ISC_MSG_RWLOCK        1705 /* "RWLOCK" */
-#define ISC_MSG_RWLOCKED       1706 /* "RWLOCKED" */
-#define ISC_MSG_RWUNLOCK       1707 /* "RWUNLOCK" */
-#define ISC_MSG_BROADCAST      1708 /* "BROADCAST" */
-#define ISC_MSG_SIGNAL        1709 /* "SIGNAL" */
-#define ISC_MSG_UTILWAIT       1710 /* "WAIT" */
-#define ISC_MSG_WAITED        1711 /* "WAITED" */
-
-#define ISC_MSG_GETIFADDRS     1801 /* "getting interface addresses: ..." */
-
+#define ISC_MSG_FAILED         101 /*%< "failed" */
+#define ISC_MSG_SUCCEEDED      102 /*%< Compatible with "failed" */
+#define ISC_MSG_SUCCESS                103 /*%< More usual way to say "success" */
+#define ISC_MSG_STARTING       104 /*%< As in "daemon: starting" */
+#define ISC_MSG_STOPING                105 /*%< As in "daemon: stopping" */
+#define ISC_MSG_ENTERING       106 /*%< As in "some_subr: entering" */
+#define ISC_MSG_EXITING                107 /*%< As in "some_subr: exiting" */
+#define ISC_MSG_CALLING                108 /*%< As in "calling some_subr()" */
+#define ISC_MSG_RETURNED       109 /*%< As in "some_subr: returned <foo>" */
+#define ISC_MSG_FATALERROR     110 /*%< "fatal error" */
+#define ISC_MSG_SHUTTINGDOWN   111 /*%< "shutting down" */
+#define ISC_MSG_RUNNING                112 /*%< "running" */
+#define ISC_MSG_WAIT           113 /*%< "wait" */
+#define ISC_MSG_WAITUNTIL      114 /*%< "waituntil" */
+
+#define ISC_MSG_SIGNALSETUP    201 /*%< "handle_signal() %d setup: %s" */
+
+#define ISC_MSG_ILLEGALOPT     301 /*%< "illegal option" */
+#define ISC_MSG_OPTNEEDARG     302 /*%< "option requires an argument" */
+
+#define ISC_MSG_ENTROPYSTATS   401 /*%< "Entropy pool %p:  refcnt %u ..." */
+
+#define ISC_MSG_MAKESCANSOCKET 501 /*%< "making interface scan socket: %s" */
+#define ISC_MSG_GETIFCONFIG    502 /*%< "get interface configuration: %s" */
+#define ISC_MSG_BUFFERMAX      503 /*%< "... maximum buffer size exceeded" */
+#define ISC_MSG_GETDESTADDR    504 /*%< "%s: getting destination address: %s" */
+#define ISC_MSG_GETNETMASK     505 /*%< "%s: getting netmask: %s" */
+
+#define ISC_MSG_GETIFLISTSIZE  601 /*%< "getting interface list size: ..." */
+#define ISC_MSG_GETIFLIST      602 /*%< "getting interface list: ..." */
+#define ISC_MSG_UNEXPECTEDTYPE 603 /*%< "... unexpected ... message type" */
+
+#define ISC_MSG_UNEXPECTEDSTATE        701 /*%< "Unexpected state %d" */
+
+#define ISC_MSG_BADTIME                801 /*%< "Bad 00 99:99:99.999 " */
+#define ISC_MSG_LEVEL          802 /*%< "level %d: " */
+
+#define ISC_MSG_ADDTRACE       901 /*%< "add %p size %u " */
+#define ISC_MSG_DELTRACE       902 /*%< "del %p size %u " */
+#define ISC_MSG_POOLSTATS      903 /*%< "[Pool statistics]\n" */
+#define ISC_MSG_POOLNAME       904 /*%< "name" */
+#define ISC_MSG_POOLSIZE       905 /*%< "size" */
+#define ISC_MSG_POOLMAXALLOC   906 /*%< "maxalloc" */
+#define ISC_MSG_POOLALLOCATED  907 /*%< "allocated" */
+#define ISC_MSG_POOLFREECOUNT  908 /*%< "freecount" */
+#define ISC_MSG_POOLFREEMAX    909 /*%< "freemax" */
+#define ISC_MSG_POOLFILLCOUNT  910 /*%< "fillcount" */
+#define ISC_MSG_POOLGETS       911 /*%< "gets" */
+#define ISC_MSG_DUMPALLOC      912 /*%< "DUMP OF ALL OUTSTANDING MEMORY ..." */
+#define ISC_MSG_NONE           913 /*%< "\tNone.\n" */
+#define ISC_MSG_PTRFILELINE    914 /*%< "\tptr %p file %s line %u\n" */
+
+#define ISC_MSG_UNKNOWNADDR    1001 /*%< "<unknown address, family %u>" */
+
+#define ISC_MSG_NOLONGDBL      1104 /*%< "long doubles are not supported" */
+
+#define ISC_MSG_PRINTLOCK      1201 /*%< "rwlock %p thread %lu ..." */
+#define ISC_MSG_READ          1202 /*%< "read" */
+#define ISC_MSG_WRITE         1203 /*%< "write" */
+#define ISC_MSG_READING               1204 /*%< "reading" */
+#define ISC_MSG_WRITING               1205 /*%< "writing" */
+#define ISC_MSG_PRELOCK               1206 /*%< "prelock" */
+#define ISC_MSG_POSTLOCK       1207 /*%< "postlock" */
+#define ISC_MSG_PREUNLOCK      1208 /*%< "preunlock" */
+#define ISC_MSG_POSTUNLOCK     1209 /*%< "postunlock" */
+
+#define ISC_MSG_UNKNOWNFAMILY  1301 /*%< "unknown address family: %d" */
+
+#define ISC_MSG_WRITEFAILED    1401 /*%< "write() failed during watcher ..." */
+#define ISC_MSG_READFAILED     1402 /*%< "read() failed during watcher ... " */
+#define ISC_MSG_PROCESSCMSG    1403 /*%< "processing cmsg %p" */
+#define ISC_MSG_IFRECEIVED     1404 /*%< "interface received on ifindex %u" */
+#define ISC_MSG_SENDTODATA     1405 /*%< "sendto pktinfo data, ifindex %u" */
+#define ISC_MSG_DOIORECV       1406 /*%< "doio_recv: recvmsg(%d) %d bytes ..." */
+#define ISC_MSG_PKTRECV               1407 /*%< "packet received correctly" */
+#define ISC_MSG_DESTROYING     1408 /*%< "destroying" */
+#define ISC_MSG_CREATED               1409 /*%< "created" */
+#define ISC_MSG_ACCEPTLOCK     1410 /*%< "internal_accept called, locked ..." */
+#define ISC_MSG_ACCEPTEDCXN    1411 /*%< "accepted connection, new socket %p" */
+#define ISC_MSG_INTERNALRECV   1412 /*%< "internal_recv: task %p got event %p" */
+#define ISC_MSG_INTERNALSEND   1413 /*%< "internal_send: task %p got event %p" */
+#define ISC_MSG_WATCHERMSG     1414 /*%< "watcher got message %d" */
+#define ISC_MSG_SOCKETSREMAIN  1415 /*%< "sockets exist" */
+#define ISC_MSG_PKTINFOPROVIDED        1416 /*%< "pktinfo structure provided, ..." */
+#define ISC_MSG_BOUND         1417 /*%< "bound" */
+#define ISC_MSG_ACCEPTRETURNED 1418 /*%< accept() returned %d/%s */
+#define ISC_MSG_TOOMANYFDS     1419 /*%< %s: too many open file descriptors */
+#define ISC_MSG_ZEROPORT       1420 /*%< dropping source port zero packet */
+#define ISC_MSG_FILTER        1421 /*%< setsockopt(SO_ACCEPTFILTER): %s */
+
+#define ISC_MSG_TOOMANYHANDLES 1422 /*%< %s: too many open WSA event handles: %s */
+
+
+#define ISC_MSG_AWAKE         1502 /*%< "awake" */
+#define ISC_MSG_WORKING               1503 /*%< "working" */
+#define ISC_MSG_EXECUTE               1504 /*%< "execute action" */
+#define ISC_MSG_EMPTY         1505 /*%< "empty" */
+#define ISC_MSG_DONE          1506 /*%< "done" */
+#define ISC_MSG_QUANTUM               1507 /*%< "quantum" */
+
+#define ISC_MSG_SCHEDULE       1601 /*%< "schedule" */
+#define ISC_MSG_SIGNALSCHED    1602 /*%< "signal (schedule)" */
+#define ISC_MSG_SIGNALDESCHED  1603 /*%< "signal (deschedule)" */
+#define ISC_MSG_SIGNALDESTROY  1604 /*%< "signal (destroy)" */
+#define ISC_MSG_IDLERESCHED    1605 /*%< "idle reschedule" */
+#define ISC_MSG_EVENTNOTALLOC  1606 /*%< "couldn't allocate event" */
+#define ISC_MSG_SCHEDFAIL      1607 /*%< "couldn't schedule timer: %u" */
+#define ISC_MSG_POSTING               1608 /*%< "posting" */
+#define ISC_MSG_WAKEUP        1609 /*%< "wakeup" */
+
+#define ISC_MSG_LOCK          1701 /*%< "LOCK" */
+#define ISC_MSG_LOCKING               1702 /*%< "LOCKING" */
+#define ISC_MSG_LOCKED        1703 /*%< "LOCKED" */
+#define ISC_MSG_UNLOCKED       1704 /*%< "UNLOCKED" */
+#define ISC_MSG_RWLOCK        1705 /*%< "RWLOCK" */
+#define ISC_MSG_RWLOCKED       1706 /*%< "RWLOCKED" */
+#define ISC_MSG_RWUNLOCK       1707 /*%< "RWUNLOCK" */
+#define ISC_MSG_BROADCAST      1708 /*%< "BROADCAST" */
+#define ISC_MSG_SIGNAL        1709 /*%< "SIGNAL" */
+#define ISC_MSG_UTILWAIT       1710 /*%< "WAIT" */
+#define ISC_MSG_WAITED        1711 /*%< "WAITED" */
+
+#define ISC_MSG_GETIFADDRS     1801 /*%< "getting interface addresses: ..." */
+
+/*@}*/
 
 #endif /* ISC_MSGS_H */
diff --git a/lib/isc/include/isc/mutexblock.h b/lib/isc/include/isc/mutexblock.h
new file mode 100644 (file)
index 0000000..65bf2bf
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: mutexblock.h,v 1.17 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_MUTEXBLOCK_H
+#define ISC_MUTEXBLOCK_H 1
+
+/*! \file isc/mutexblock.h */
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_mutexblock_init(isc_mutex_t *block, unsigned int count);
+/*%<
+ * Initialize a block of locks.  If an error occurs all initialized locks
+ * will be destroyed, if possible.
+ *
+ * Requires:
+ *
+ *\li  block != NULL
+ *
+ *\li  count > 0
+ *
+ * Returns:
+ *
+ *\li  Any code isc_mutex_init() can return is a valid return for this
+ *     function.
+ */
+
+isc_result_t
+isc_mutexblock_destroy(isc_mutex_t *block, unsigned int count);
+/*%<
+ * Destroy a block of locks.
+ *
+ * Requires:
+ *
+ *\li  block != NULL
+ *
+ *\li  count > 0
+ *
+ *\li  Each lock in the block be initialized via isc_mutex_init() or
+ *     the whole block was initialized via isc_mutex_initblock().
+ *
+ * Returns:
+ *
+ *\li  Any code isc_mutex_init() can return is a valid return for this
+ *     function.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_MUTEXBLOCK_H */
index e209a9fa77497663ad933e16014e511f23bc8b6c..8bfdbce20c12dbac96470f62852a93603c3ac839 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: netaddr.h,v 1.18.12.7 2004/03/08 09:04:52 marka Exp $ */
+/* $Id: netaddr.h,v 1.35.332.2 2009/01/18 23:47:41 tbox Exp $ */
 
 #ifndef ISC_NETADDR_H
 #define ISC_NETADDR_H 1
 
+/*! \file isc/netaddr.h */
+
 #include <isc/lang.h>
 #include <isc/net.h>
 #include <isc/types.h>
 
+#ifdef ISC_PLATFORM_HAVESYSUNH
+#include <sys/types.h>
+#include <sys/un.h>
+#endif
+
 ISC_LANG_BEGINDECLS
 
 struct isc_netaddr {
        unsigned int family;
        union {
-               struct in_addr in;
+               struct in_addr in;
                struct in6_addr in6;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+               char un[sizeof(((struct sockaddr_un *)0)->sun_path)];
+#endif
        } type;
        isc_uint32_t zone;
 };
@@ -38,51 +48,56 @@ struct isc_netaddr {
 isc_boolean_t
 isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b);
 
+/*%<
+ * Compare network addresses 'a' and 'b'.  Return #ISC_TRUE if
+ * they are equal, #ISC_FALSE if not.
+ */
+
 isc_boolean_t
 isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
                     unsigned int prefixlen);
-/*
+/*%<
  * Compare the 'prefixlen' most significant bits of the network
- * addresses 'a' and 'b'.  Return ISC_TRUE if they are equal,
- * ISC_FALSE if not.
+ * addresses 'a' and 'b'.  If 'b''s scope is zero then 'a''s scope is
+ * ignored.  Return #ISC_TRUE if they are equal, #ISC_FALSE if not.
  */
 
 isc_result_t
 isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp);
-/*
+/*%<
  * Convert a netmask in 's' into a prefix length in '*lenp'.
  * The mask should consist of zero or more '1' bits in the most
  * most significant part of the address, followed by '0' bits.
- * If this is not the case, ISC_R_MASKNONCONTIG is returned.
+ * If this is not the case, #ISC_R_MASKNONCONTIG is returned.
  *
  * Returns:
- *     ISC_R_SUCCESS
- *     ISC_R_MASKNONCONTIG
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_MASKNONCONTIG
  */
 
 isc_result_t
 isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target);
-/*
+/*%<
  * Append a text representation of 'sockaddr' to the buffer 'target'.
  * The text is NOT null terminated.  Handles IPv4 and IPv6 addresses.
  *
  * Returns:
- *     ISC_R_SUCCESS
- *     ISC_R_NOSPACE   The text or the null termination did not fit.
- *     ISC_R_FAILURE   Unspecified failure
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOSPACE  The text or the null termination did not fit.
+ *\li  #ISC_R_FAILURE  Unspecified failure
  */
 
 void
 isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size);
-/*
+/*%<
  * Format a human-readable representation of the network address '*na'
  * into the character array 'array', which is of size 'size'.
  * The resulting string is guaranteed to be null-terminated.
  */
 
 #define ISC_NETADDR_FORMATSIZE \
-       sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX")
-/*
+       sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS")
+/*%<
  * Minimum size of array to pass to isc_netaddr_format().
  */
 
@@ -95,6 +110,9 @@ isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina);
 void
 isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6);
 
+isc_result_t
+isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path);
+
 void
 isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone);
 
@@ -103,46 +121,59 @@ isc_netaddr_getzone(const isc_netaddr_t *netaddr);
 
 void
 isc_netaddr_any(isc_netaddr_t *netaddr);
-/*
+/*%<
  * Return the IPv4 wildcard address.
  */
 
 void
 isc_netaddr_any6(isc_netaddr_t *netaddr);
-/*
+/*%<
  * Return the IPv6 wildcard address.
  */
 
 isc_boolean_t
 isc_netaddr_ismulticast(isc_netaddr_t *na);
-/*
+/*%<
  * Returns ISC_TRUE if the address is a multicast address.
  */
 
 isc_boolean_t
 isc_netaddr_isexperimental(isc_netaddr_t *na);
-/*
+/*%<
  * Returns ISC_TRUE if the address is a experimental (CLASS E) address.
  */
 
 isc_boolean_t
 isc_netaddr_islinklocal(isc_netaddr_t *na);
-/*
- * Returns ISC_TRUE if the address is a link local address.
+/*%<
+ * Returns #ISC_TRUE if the address is a link local address.
  */
 
 isc_boolean_t
 isc_netaddr_issitelocal(isc_netaddr_t *na);
-/*
- * Returns ISC_TRUE if the address is a site local address.
+/*%<
+ * Returns #ISC_TRUE if the address is a site local address.
  */
 
 void
 isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s);
-/*
+/*%<
  * Convert an IPv6 v4mapped address into an IPv4 address.
  */
 
+isc_result_t
+isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen);
+/*
+ * Test whether the netaddr 'na' and 'prefixlen' are consistant.
+ * e.g. prefixlen within range.
+ *      na does not have bits set which are not covered by the prefixlen.
+ *
+ * Returns:
+ *     ISC_R_SUCCESS
+ *     ISC_R_RANGE             prefixlen out of range
+ *     ISC_R_NOTIMPLEMENTED    unsupported family
+ *     ISC_R_FAILURE           extra bits.
+ */
 
 ISC_LANG_ENDDECLS
 
index 7cc0f182d7424a963833bad2efc6e5b84d17f79c..ba4e792a40a4675cad3ae05140c9d12e5e63ca6d 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: netscope.h,v 1.4.142.5 2004/03/08 09:04:52 marka Exp $ */
+/* $Id: netscope.h,v 1.11 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_NETSCOPE_H
 #define ISC_NETSCOPE_H 1
 
+/*! \file isc/netscope.h */
+
 ISC_LANG_BEGINDECLS
 
-/*
+/*%
  * Convert a string of an IPv6 scope zone to zone index.  If the conversion
  * succeeds, 'zoneid' will store the index value.
+ *
  * XXXJT: when a standard interface for this purpose is defined,
  * we should use it.
  *
  * Returns:
- *     ISC_R_SUCCESS: conversion succeeds
- *     ISC_R_FAILURE: conversion fails
+ * \li ISC_R_SUCCESS: conversion succeeds
+ * \li ISC_R_FAILURE: conversion fails
  */
 isc_result_t
 isc_netscope_pton(int af, char *scopename, void *addr, isc_uint32_t *zoneid);
diff --git a/lib/isc/include/isc/ondestroy.h b/lib/isc/include/isc/ondestroy.h
new file mode 100644 (file)
index 0000000..64bd643
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ondestroy.h,v 1.14 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_ONDESTROY_H
+#define ISC_ONDESTROY_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*! \file isc/ondestroy.h
+ * ondestroy handling.
+ *
+ * Any class ``X'' of objects that wants to send out notifications
+ * on its destruction should declare a field of type isc_ondestroy_t
+ * (call it 'ondest').
+ *
+ * \code
+ *     typedef struct {
+ *             ...
+ *             isc_ondestroy_t ondest;
+ *             ...
+ *     } X;
+ * \endcode
+ *
+ * When an object ``A'' of type X is created
+ * it must initialize the field ondest with a call to
+ *
+ * \code
+ *     isc_ondestroy_init(&A->ondest).
+ * \endcode
+ *
+ * X should also provide a registration function for third-party
+ * objects to call to register their interest in being told about
+ * the destruction of a particular instance of X.
+ *
+ * \code
+ *     isc_result_t
+ *     X_ondestroy(X *instance, isc_task_t *task,
+ *                  isc_event_t **eventp) {
+ *             return(isc_ondestroy_register(&instance->ondest, task,eventp));
+ *     }
+ * \endcode
+ *
+ *     Note: locking of the ondestory structure embedded inside of X, is
+ *     X's responsibility.
+ *
+ * When an instance of X is destroyed, a call to  isc_ondestroy_notify()
+ * sends the notifications:
+ *
+ * \code
+ *     X *instance;
+ *     isc_ondestroy_t ondest = instance->ondest;
+ *
+ *     ... completely cleanup 'instance' here...
+ *
+ *     isc_ondestroy_notify(&ondest, instance);
+ * \endcode
+ *
+ *
+ * see lib/dns/zone.c for an ifdef'd-out example.
+ */
+
+struct isc_ondestroy {
+       unsigned int magic;
+       isc_eventlist_t events;
+};
+
+void
+isc_ondestroy_init(isc_ondestroy_t *ondest);
+/*%<
+ * Initialize the on ondest structure. *must* be called before first call
+ * to isc_ondestroy_register().
+ */
+
+isc_result_t
+isc_ondestroy_register(isc_ondestroy_t *ondest, isc_task_t *task,
+                      isc_event_t **eventp);
+
+/*%<
+ * Stores task and *eventp away inside *ondest.  Ownership of **event is
+ * taken from the caller (and *eventp is set to NULL). The task is attached
+ * to.
+ */
+
+void
+isc_ondestroy_notify(isc_ondestroy_t *ondest, void *sender);
+/*%<
+ * Dispatches the event(s) to the task(s) that were given in
+ * isc_ondestroy_register call(s) (done via calls to
+ * isc_task_sendanddetach()).  Before dispatch, the sender value of each
+ * event structure is set to the value of the sender paramater. The
+ * internal structures of the ondest parameter are cleaned out, so no other
+ * cleanup is needed.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ONDESTROY_H */
diff --git a/lib/isc/include/isc/os.h b/lib/isc/include/isc/os.h
new file mode 100644 (file)
index 0000000..3cf59e2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: os.h,v 1.12 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_OS_H
+#define ISC_OS_H 1
+
+/*! \file isc/os.h */
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+unsigned int
+isc_os_ncpus(void);
+/*%<
+ * Return the number of CPUs available on the system, or 1 if this cannot
+ * be determined.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_OS_H */
diff --git a/lib/isc/include/isc/parseint.h b/lib/isc/include/isc/parseint.h
new file mode 100644 (file)
index 0000000..5047676
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001, 2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: parseint.h,v 1.9 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_PARSEINT_H
+#define ISC_PARSEINT_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file isc/parseint.h
+ * \brief Parse integers, in a saner way than atoi() or strtoul() do.
+ */
+
+/***
+ ***   Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_parse_uint32(isc_uint32_t *uip, const char *string, int base);
+
+isc_result_t
+isc_parse_uint16(isc_uint16_t *uip, const char *string, int base);
+
+isc_result_t
+isc_parse_uint8(isc_uint8_t *uip, const char *string, int base);
+/*%<
+ * Parse the null-terminated string 'string' containing a base 'base'
+ * integer, storing the result in '*uip'.  
+ * The base is interpreted
+ * as in strtoul().  Unlike strtoul(), leading whitespace, minus or
+ * plus signs are not accepted, and all errors (including overflow)
+ * are reported uniformly through the return value.
+ *
+ * Requires:
+ *\li  'string' points to a null-terminated string
+ *\li  0 <= 'base' <= 36
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_BADNUMBER   The string is not numeric (in the given base)
+ *\li  #ISC_R_RANGE      The number is not representable as the requested type.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_PARSEINT_H */
diff --git a/lib/isc/include/isc/platform.h.in b/lib/isc/include/isc/platform.h.in
new file mode 100644 (file)
index 0000000..1ed76b8
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: platform.h.in,v 1.48.84.2 2009/02/16 23:47:15 tbox Exp $ */
+
+#ifndef ISC_PLATFORM_H
+#define ISC_PLATFORM_H 1
+
+/*! \file */
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+/***
+ *** Network.
+ ***/
+
+/*! \brief
+ * Define if this system needs the <netinet/in6.h> header file included
+ * for full IPv6 support (pretty much only UnixWare).
+ */
+@ISC_PLATFORM_NEEDNETINETIN6H@
+
+/*! \brief
+ * Define if this system needs the <netinet6/in6.h> header file included
+ * to support in6_pkinfo (pretty much only BSD/OS).
+ */
+@ISC_PLATFORM_NEEDNETINET6IN6H@
+
+/*! \brief
+ * If sockaddrs on this system have an sa_len field, ISC_PLATFORM_HAVESALEN
+ * will be defined.
+ */
+@ISC_PLATFORM_HAVESALEN@
+
+/*! \brief
+ * If this system has the IPv6 structure definitions, ISC_PLATFORM_HAVEIPV6
+ * will be defined.
+ */
+@ISC_PLATFORM_HAVEIPV6@
+
+/*! \brief
+ * If this system is missing in6addr_any, ISC_PLATFORM_NEEDIN6ADDRANY will
+ * be defined.
+ */
+@ISC_PLATFORM_NEEDIN6ADDRANY@
+
+/*! \brief
+ * If this system is missing in6addr_loopback, ISC_PLATFORM_NEEDIN6ADDRLOOPBACK
+ * will be defined.
+ */
+@ISC_PLATFORM_NEEDIN6ADDRLOOPBACK@
+
+/*! \brief
+ * If this system has in6_pktinfo, ISC_PLATFORM_HAVEIN6PKTINFO will be
+ * defined.
+ */
+@ISC_PLATFORM_HAVEIN6PKTINFO@
+
+/*! \brief
+ * If this system has in_addr6, rather than in6_addr, ISC_PLATFORM_HAVEINADDR6
+ * will be defined.
+ */
+@ISC_PLATFORM_HAVEINADDR6@
+
+/*! \brief
+ * If this system has sin6_scope_id, ISC_PLATFORM_HAVESCOPEID will be defined.
+ */
+@ISC_PLATFORM_HAVESCOPEID@
+
+/*! \brief
+ * If this system needs inet_ntop(), ISC_PLATFORM_NEEDNTOP will be defined.
+ */
+@ISC_PLATFORM_NEEDNTOP@
+
+/*! \brief
+ * If this system needs inet_pton(), ISC_PLATFORM_NEEDPTON will be defined.
+ */
+@ISC_PLATFORM_NEEDPTON@
+
+/*! \brief
+ * If this system needs in_port_t, ISC_PLATFORM_NEEDPORTT will be defined.
+ */
+@ISC_PLATFORM_NEEDPORTT@
+
+/*! \brief
+ * Define if the system has struct lifconf which is a extended struct ifconf
+ * for IPv6.
+ */
+@ISC_PLATFORM_HAVELIFCONF@
+
+/*! \brief
+ * Define if the system has struct if_laddrconf which is a extended struct
+ * ifconf for IPv6.
+ */
+@ISC_PLATFORM_HAVEIF_LADDRCONF@
+
+/*! \brief
+ * Define if the system has struct if_laddrreq.
+ */
+@ISC_PLATFORM_HAVEIF_LADDRREQ@
+
+/*! \brief
+ * Define either ISC_PLATFORM_BSD44MSGHDR or ISC_PLATFORM_BSD43MSGHDR.
+ */
+@ISC_PLATFORM_MSGHDRFLAVOR@
+
+/*! \brief
+ * Define if the system supports if_nametoindex.
+ */
+@ISC_PLATFORM_HAVEIFNAMETOINDEX@
+
+/*! \brief
+ * Define on some UnixWare systems to fix erroneous definitions of various
+ * IN6_IS_ADDR_* macros.
+ */
+@ISC_PLATFORM_FIXIN6ISADDR@
+
+/*! \brief
+ * Define if the system supports kqueue multiplexing
+ */
+@ISC_PLATFORM_HAVEKQUEUE@
+
+/*! \brief
+ * Define if the system supports epoll multiplexing
+ */
+@ISC_PLATFORM_HAVEEPOLL@
+
+/*! \brief
+ * Define if the system supports /dev/poll multiplexing
+ */
+@ISC_PLATFORM_HAVEDEVPOLL@
+
+/*
+ *** Printing.
+ ***/
+
+/*! \brief
+ * If this system needs vsnprintf() and snprintf(), ISC_PLATFORM_NEEDVSNPRINTF
+ * will be defined.
+ */
+@ISC_PLATFORM_NEEDVSNPRINTF@
+
+/*! \brief
+ * If this system need a modern sprintf() that returns (int) not (char*).
+ */
+@ISC_PLATFORM_NEEDSPRINTF@
+
+/*! \brief
+ * The printf format string modifier to use with isc_uint64_t values.
+ */
+@ISC_PLATFORM_QUADFORMAT@
+
+/***
+ *** String functions.
+ ***/
+/*
+ * If the system needs strsep(), ISC_PLATFORM_NEEDSTRSEP will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRSEP@
+
+/*
+ * If the system needs strlcpy(), ISC_PLATFORM_NEEDSTRLCPY will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRLCPY@
+
+/*
+ * If the system needs strlcat(), ISC_PLATFORM_NEEDSTRLCAT will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRLCAT@
+
+/*
+ * Define if this system needs strtoul.
+ */
+@ISC_PLATFORM_NEEDSTRTOUL@
+
+/*
+ * Define if this system needs memmove.
+ */
+@ISC_PLATFORM_NEEDMEMMOVE@
+
+/***
+ *** Miscellaneous.
+ ***/
+
+/*
+ * Defined if we are using threads.
+ */
+@ISC_PLATFORM_USETHREADS@
+
+/*
+ * Defined if unistd.h does not cause fd_set to be delared.
+ */
+@ISC_PLATFORM_NEEDSYSSELECTH@
+
+/*
+ * Defined to <gssapi.h> or <gssapi/gssapi.h> for how to include
+ * the GSSAPI header.
+ */
+@ISC_PLATFORM_GSSAPIHEADER@
+
+/*
+ * Type used for resource limits.
+ */
+@ISC_PLATFORM_RLIMITTYPE@
+
+/*
+ * Define if your compiler supports "long long int".
+ */
+@ISC_PLATFORM_HAVELONGLONG@
+
+/*
+ * Define if PTHREAD_ONCE_INIT should be surrounded by braces to
+ * prevent compiler warnings (such as with gcc on Solaris 2.8).
+ */
+@ISC_PLATFORM_BRACEPTHREADONCEINIT@
+
+/*
+ * Used to control how extern data is linked; needed for Win32 platforms.
+ */
+@ISC_PLATFORM_USEDECLSPEC@
+
+/*
+ * Define if the platform has <sys/un.h>.
+ */
+@ISC_PLATFORM_HAVESYSUNH@
+
+/*
+ * If the "xadd" operation is available on this architecture,
+ * ISC_PLATFORM_HAVEXADD will be defined.
+ */
+@ISC_PLATFORM_HAVEXADD@
+
+/*
+ * If the "xaddq" operation (64bit xadd) is available on this architecture,
+ * ISC_PLATFORM_HAVEXADDQ will be defined.
+ */
+@ISC_PLATFORM_HAVEXADDQ@
+
+/*
+ * If the "atomic swap" operation is available on this architecture,
+ * ISC_PLATFORM_HAVEATOMICSTORE" will be defined.
+ */
+@ISC_PLATFORM_HAVEATOMICSTORE@
+
+/*
+ * If the "compare-and-exchange" operation is available on this architecture,
+ * ISC_PLATFORM_HAVECMPXCHG will be defined.
+ */
+@ISC_PLATFORM_HAVECMPXCHG@
+
+/*
+ * Define if gcc ASM extension is available
+ */
+@ISC_PLATFORM_USEGCCASM@
+
+/*
+ * Define if Tru64 style ASM syntax must be used.
+ */
+@ISC_PLATFORM_USEOSFASM@
+
+/*
+ * Define if the standard __asm function must be used.
+ */
+@ISC_PLATFORM_USESTDASM@
+
+/*
+ * Define if the platform has <strings.h>.
+ */
+@ISC_PLATFORM_HAVESTRINGSH@
+
+/***
+ ***   Windows dll support.
+ ***/
+
+/*
+ * Define if MacOS style of PPC assembly must be used.
+ * e.g. "r6", not "6", for register six.
+ */
+@ISC_PLATFORM_USEMACASM@
+
+#ifndef ISC_PLATFORM_USEDECLSPEC
+#define LIBISC_EXTERNAL_DATA
+#define LIBDNS_EXTERNAL_DATA
+#define LIBISCCC_EXTERNAL_DATA
+#define LIBISCCFG_EXTERNAL_DATA
+#define LIBBIND9_EXTERNAL_DATA
+#else /*! \brief ISC_PLATFORM_USEDECLSPEC */
+#ifdef LIBISC_EXPORTS
+#define LIBISC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBDNS_EXPORTS
+#define LIBDNS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBDNS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBISCCC_EXPORTS
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBISCCFG_EXPORTS
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#ifdef LIBBIND9_EXPORTS
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllimport)
+#endif
+#endif /*! \brief ISC_PLATFORM_USEDECLSPEC */
+
+/*
+ * Tell emacs to use C mode for this file.
+ *
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
+#endif /* ISC_PLATFORM_H */
diff --git a/lib/isc/include/isc/portset.h b/lib/isc/include/isc/portset.h
new file mode 100644 (file)
index 0000000..dc1f856
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2008, 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: portset.h,v 1.3.90.2 2009/01/18 23:47:41 tbox Exp $ */
+
+/*! \file isc/portset.h
+ * \brief Transport Protocol Port Manipulation Module
+ *
+ * This module provides simple utilities to handle a set of transport protocol
+ * (UDP or TCP) port numbers, e.g., for creating an ACL list.  An isc_portset_t
+ * object is an opaque instance of a port set, for which the user can add or
+ * remove a specific port or a range of consecutive ports.  This object is
+ * expected to be used as a temporary work space only, and does not protect
+ * simultaneous access from multiple threads.  Therefore it must not be stored
+ * in a place that can be accessed from multiple threads.
+ */
+
+#ifndef ISC_PORTSET_H
+#define ISC_PORTSET_H 1
+
+/***
+ ***   Imports
+ ***/
+
+#include <isc/net.h>
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp);
+/*%<
+ * Create a port set and initialize it as an empty set.
+ *
+ * Requires:
+ *\li  'mctx' to be valid.
+ *\li  'portsetp' to be non NULL and '*portsetp' to be NULL;
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ */
+
+void
+isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp);
+/*%<
+ * Destroy a port set.
+ *
+ * Requires:
+ *\li  'mctx' to be valid and must be the same context given when the port set
+ *       was created.
+ *\li  '*portsetp' to be a valid set.
+ */
+
+isc_boolean_t
+isc_portset_isset(isc_portset_t *portset, in_port_t port);
+/*%<
+ * Test whether the given port is stored in the portset.
+ *
+ * Requires:
+ *\li  'portset' to be a valid set.
+ *
+ * Returns
+ * \li #ISC_TRUE if the port is found, ISC_FALSE otherwise.
+ */
+
+unsigned int
+isc_portset_nports(isc_portset_t *portset);
+/*%<
+ * Provides the number of ports stored in the given portset.
+ *
+ * Requires:
+ *\li  'portset' to be a valid set.
+ *
+ * Returns
+ * \li the number of ports stored in portset.
+ */
+
+void
+isc_portset_add(isc_portset_t *portset, in_port_t port);
+/*%<
+ * Add the given port to the portset.  The port may or may not be stored in
+ * the portset.
+ *
+ * Requires:
+ *\li  'portlist' to be valid.
+ */
+
+void
+isc_portset_remove(isc_portset_t *portset, in_port_t port);
+/*%<
+ * Remove the given port to the portset.  The port may or may not be stored in
+ * the portset.
+ *
+ * Requires:
+ *\li  'portlist' to be valid.
+ */
+
+void
+isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo,
+                    in_port_t port_hi);
+/*%<
+ * Add a subset of [port_lo, port_hi] (inclusive) to the portset.  Ports in the
+ * subset may or may not be stored in portset.
+ *
+ * Requires:
+ *\li  'portlist' to be valid.
+ *\li  port_lo <= port_hi
+ */
+
+void
+isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo,
+                       in_port_t port_hi);
+/*%<
+ * Subtract a subset of [port_lo, port_hi] (inclusive) from the portset.  Ports
+ * in the subset may or may not be stored in portset.
+ *
+ * Requires:
+ *\li  'portlist' to be valid.
+ *\li  port_lo <= port_hi
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NETADDR_H */
index 7a1bc83b6741b35427ecae74fe7de7a4200b071f..cd1e38eaf6fb1e91ae642f9452dc215535189d06 100644 (file)
@@ -1,25 +1,27 @@
 /*
- * Copyright (C) 1999-2001  Internet Software Consortium.
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: print.h,v 1.17 2001/02/27 02:19:33 gson Exp $ */
+/* $Id: print.h,v 1.26 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_PRINT_H
 #define ISC_PRINT_H 1
 
+/*! \file isc/print.h */
+
 /***
  *** Imports
  ***/
@@ -28,7 +30,7 @@
 #include <isc/lang.h>
 #include <isc/platform.h>
 
-/*
+/*!
  * This block allows lib/isc/print.c to be cleanly compiled even if
  * the platform does not need it.  The standard Makefile will still
  * not compile print.c or archive print.o, so this is just to make test
 #define ISC_PLATFORM_NEEDVSNPRINTF
 #endif
 
+#if !defined(ISC_PLATFORM_NEEDSPRINTF) && defined(ISC__PRINT_SOURCE)
+#define ISC_PLATFORM_NEEDSPRINTF
+#endif
+
 /***
  *** Macros
  ***/
 #ifdef ISC_PLATFORM_NEEDVSNPRINTF
 #include <stdarg.h>
 #include <stddef.h>
+#endif
+#ifdef ISC_PLATFORM_NEEDSPRINTF
+#include <stdio.h>
+#endif
+
 
 ISC_LANG_BEGINDECLS
 
+#ifdef ISC_PLATFORM_NEEDVSNPRINTF
 int
 isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap)
      ISC_FORMAT_PRINTF(3, 0);
@@ -62,8 +74,14 @@ int
 isc_print_snprintf(char *str, size_t size, const char *format, ...)
      ISC_FORMAT_PRINTF(3, 4);
 #define snprintf isc_print_snprintf
+#endif /* ISC_PLATFORM_NEEDVSNPRINTF */
+
+#ifdef ISC_PLATFORM_NEEDSPRINTF
+int
+isc_print_sprintf(char *str, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
+#define sprintf isc_print_sprintf
+#endif
 
 ISC_LANG_ENDDECLS
-#endif /* ISC_PLATFORM_NEEDVSNPRINTF */
 
 #endif /* ISC_PRINT_H */
diff --git a/lib/isc/include/isc/quota.h b/lib/isc/include/isc/quota.h
new file mode 100644 (file)
index 0000000..7b0d0d9
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: quota.h,v 1.16 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_QUOTA_H
+#define ISC_QUOTA_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/quota.h
+ *
+ * \brief The isc_quota_t object is a simple helper object for implementing
+ * quotas on things like the number of simultaneous connections to
+ * a server.  It keeps track of the amount of quota in use, and
+ * encapsulates the locking necessary to allow multiple tasks to
+ * share a quota.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+/*****
+ ***** Types.
+ *****/
+
+ISC_LANG_BEGINDECLS
+
+/*% isc_quota structure */
+struct isc_quota {
+       isc_mutex_t     lock; /*%< Locked by lock. */
+       int             max;
+       int             used;
+       int             soft;
+};
+
+isc_result_t
+isc_quota_init(isc_quota_t *quota, int max);
+/*%<
+ * Initialize a quota object.
+ *
+ * Returns:
+ *     ISC_R_SUCCESS
+ *     Other error     Lock creation failed.
+ */
+
+void
+isc_quota_destroy(isc_quota_t *quota);
+/*%<
+ * Destroy a quota object.
+ */
+
+void
+isc_quota_soft(isc_quota_t *quota, int soft);
+/*%<
+ * Set a soft quota.
+ */
+
+void
+isc_quota_max(isc_quota_t *quota, int max);
+/*%<
+ * Re-set a maximum quota.
+ */
+
+isc_result_t
+isc_quota_reserve(isc_quota_t *quota);
+/*%<
+ * Attempt to reserve one unit of 'quota'.
+ *
+ * Returns:
+ * \li         #ISC_R_SUCCESS          Success
+ * \li #ISC_R_SOFTQUOTA        Success soft quota reached
+ * \li #ISC_R_QUOTA            Quota is full
+ */
+
+void
+isc_quota_release(isc_quota_t *quota);
+/*%<
+ * Release one unit of quota.
+ */
+
+isc_result_t
+isc_quota_attach(isc_quota_t *quota, isc_quota_t **p);
+/*%<
+ * Like isc_quota_reserve, and also attaches '*p' to the
+ * quota if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA).
+ */
+
+void
+isc_quota_detach(isc_quota_t **p);
+/*%<
+ * Like isc_quota_release, and also detaches '*p' from the
+ * quota.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_QUOTA_H */
diff --git a/lib/isc/include/isc/radix.h b/lib/isc/include/isc/radix.h
new file mode 100644 (file)
index 0000000..fbb1893
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: radix.h,v 1.11.44.2 2008/12/24 23:47:02 tbox Exp $ */
+
+/*
+ * This source was adapted from MRT's RCS Ids:
+ * Id: radix.h,v 1.6 1999/08/03 03:32:53 masaki Exp
+ * Id: mrt.h,v 1.57.2.6 1999/12/28 23:41:27 labovit Exp
+ * Id: defs.h,v 1.5.2.2 2000/01/15 14:19:16 masaki Exp
+ */
+
+#include <isc/magic.h>
+#include <isc/types.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/refcount.h>
+
+#include <string.h>
+
+#ifndef _RADIX_H
+#define _RADIX_H
+
+#define NETADDR_TO_PREFIX_T(na,pt,bits) \
+       do { \
+               memset(&(pt), 0, sizeof(pt)); \
+               if((na) != NULL) { \
+                       (pt).family = (na)->family; \
+                       (pt).bitlen = (bits); \
+                       if ((pt).family == AF_INET6) { \
+                               memcpy(&(pt).add.sin6, &(na)->type.in6, \
+                                      ((bits)+7)/8); \
+                       } else \
+                               memcpy(&(pt).add.sin, &(na)->type.in, \
+                                      ((bits)+7)/8); \
+               } else { \
+                       (pt).family = AF_UNSPEC; \
+                       (pt).bitlen = 0; \
+               } \
+               isc_refcount_init(&(pt).refcount, 0); \
+       } while(0)
+
+typedef struct isc_prefix {
+    unsigned int family;       /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */
+    unsigned int bitlen;       /* 0 for "any" */
+    isc_refcount_t refcount;
+    union {
+               struct in_addr sin;
+               struct in6_addr sin6;
+    } add;
+} isc_prefix_t;
+
+typedef void (*isc_radix_destroyfunc_t)(void *);
+typedef void (*isc_radix_processfunc_t)(isc_prefix_t *, void **);
+
+#define isc_prefix_tochar(prefix) ((char *)&(prefix)->add.sin)
+#define isc_prefix_touchar(prefix) ((u_char *)&(prefix)->add.sin)
+
+#define BIT_TEST(f, b)  ((f) & (b))
+
+/*
+ * We need "first match" when we search the radix tree to preserve
+ * compatibility with the existing ACL implementation. Radix trees
+ * naturally lend themselves to "best match". In order to get "first match"
+ * behavior, we keep track of the order in which entries are added to the
+ * tree--and when a search is made, we find all matching entries, and
+ * return the one that was added first.
+ *
+ * An IPv4 prefix and an IPv6 prefix may share a radix tree node if they
+ * have the same length and bit pattern (e.g., 127/8 and 7f::/8).  To
+ * disambiguate between them, node_num and data are two-element arrays;
+ * node_num[0] and data[0] are used for IPv4 addresses, node_num[1]
+ * and data[1] for IPv6 addresses.  The only exception is a prefix of
+ * 0/0 (aka "any" or "none"), which is always stored as IPv4 but matches
+ * IPv6 addresses too.
+ */
+
+#define ISC_IS6(family) ((family) == AF_INET6 ? 1 : 0)
+typedef struct isc_radix_node {
+   isc_uint32_t bit;                   /* bit length of the prefix */
+   isc_prefix_t *prefix;               /* who we are in radix tree */
+   struct isc_radix_node *l, *r;       /* left and right children */
+   struct isc_radix_node *parent;      /* may be used */
+   void *data[2];                      /* pointers to IPv4 and IPV6 data */
+   int node_num[2];                    /* which node this was in the tree,
+                                          or -1 for glue nodes */
+} isc_radix_node_t;
+
+#define RADIX_TREE_MAGIC         ISC_MAGIC('R','d','x','T');
+#define RADIX_TREE_VALID(a)      ISC_MAGIC_VALID(a, RADIX_TREE_MAGIC);
+
+typedef struct isc_radix_tree {
+   unsigned int                magic;
+   isc_mem_t           *mctx;
+   isc_radix_node_t    *head;
+   isc_uint32_t                maxbits;        /* for IP, 32 bit addresses */
+   int num_active_node;                        /* for debugging purposes */
+   int num_added_node;                 /* total number of nodes */
+} isc_radix_tree_t;
+
+isc_result_t
+isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target,
+                isc_prefix_t *prefix);
+/*%<
+ * Search 'radix' for the best match to 'prefix'.
+ * Return the node found in '*target'.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'target' is not NULL and "*target" is NULL.
+ * \li 'prefix' to be valid.
+ *
+ * Returns:
+ * \li ISC_R_NOTFOUND
+ * \li ISC_R_SUCCESS
+ */
+
+isc_result_t
+isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
+                isc_radix_node_t *source, isc_prefix_t *prefix);
+/*%<
+ * Insert 'source' or 'prefix' into the radix tree 'radix'.
+ * Return the node added in 'target'.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'target' is not NULL and "*target" is NULL.
+ * \li 'prefix' to be valid or 'source' to be non NULL and contain
+ *     a valid prefix.
+ *
+ * Returns:
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_SUCCESS
+ */
+
+void
+isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node);
+/*%<
+ * Remove the node 'node' from the radix tree 'radix'.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'node' to be valid.
+ */
+
+isc_result_t
+isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, int maxbits);
+/*%<
+ * Create a radix tree with a maximum depth of 'maxbits';
+ *
+ * Requires:
+ * \li 'mctx' to be valid.
+ * \li 'target' to be non NULL and '*target' to be NULL.
+ * \li 'maxbits' to be less than or equal to RADIX_MAXBITS.
+ *
+ * Returns:
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_SUCCESS
+ */
+
+void
+isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func);
+/*%<
+ * Destroy a radix tree optionally calling 'func' to clean up node data.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ */
+
+void
+isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func);
+/*%<
+ * Walk a radix tree calling 'func' to process node data.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'func' to point to a function.
+ */
+
+#define RADIX_MAXBITS 128
+#define RADIX_NBIT(x)        (0x80 >> ((x) & 0x7f))
+#define RADIX_NBYTE(x)       ((x) >> 3)
+
+#define RADIX_DATA_GET(node, type) (type *)((node)->data)
+#define RADIX_DATA_SET(node, value) ((node)->data = (void *)(value))
+
+#define RADIX_WALK(Xhead, Xnode) \
+    do { \
+       isc_radix_node_t *Xstack[RADIX_MAXBITS+1]; \
+       isc_radix_node_t **Xsp = Xstack; \
+       isc_radix_node_t *Xrn = (Xhead); \
+       while ((Xnode = Xrn)) { \
+           if (Xnode->prefix)
+
+#define RADIX_WALK_ALL(Xhead, Xnode) \
+do { \
+       isc_radix_node_t *Xstack[RADIX_MAXBITS+1]; \
+       isc_radix_node_t **Xsp = Xstack; \
+       isc_radix_node_t *Xrn = (Xhead); \
+       while ((Xnode = Xrn)) { \
+           if (1)
+
+#define RADIX_WALK_BREAK { \
+           if (Xsp != Xstack) { \
+               Xrn = *(--Xsp); \
+            } else { \
+               Xrn = (radix_node_t *) 0; \
+           } \
+           continue; }
+
+#define RADIX_WALK_END \
+           if (Xrn->l) { \
+               if (Xrn->r) { \
+                   *Xsp++ = Xrn->r; \
+               } \
+               Xrn = Xrn->l; \
+           } else if (Xrn->r) { \
+               Xrn = Xrn->r; \
+           } else if (Xsp != Xstack) { \
+               Xrn = *(--Xsp); \
+           } else { \
+               Xrn = (isc_radix_node_t *) 0; \
+           } \
+       } \
+    } while (0)
+
+#endif /* _RADIX_H */
diff --git a/lib/isc/include/isc/random.h b/lib/isc/include/isc/random.h
new file mode 100644 (file)
index 0000000..9b6ca64
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: random.h,v 1.18.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef ISC_RANDOM_H
+#define ISC_RANDOM_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file isc/random.h
+ * \brief Implements a random state pool which will let the caller return a
+ * series of possibly non-reproducible random values.
+ *
+ * Note that the
+ * strength of these numbers is not all that high, and should not be
+ * used in cryptography functions.  It is useful for jittering values
+ * a bit here and there, such as timeouts, etc.
+ */
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_random_seed(isc_uint32_t seed);
+/*%<
+ * Set the initial seed of the random state.
+ */
+
+void
+isc_random_get(isc_uint32_t *val);
+/*%<
+ * Get a random value.
+ *
+ * Requires:
+ *     val != NULL.
+ */
+
+isc_uint32_t
+isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter);
+/*%<
+ * Get a random value between (max - jitter) and (max).
+ * This is useful for jittering timer values.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RANDOM_H */
diff --git a/lib/isc/include/isc/ratelimiter.h b/lib/isc/include/isc/ratelimiter.h
new file mode 100644 (file)
index 0000000..d18cf25
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ratelimiter.h,v 1.21.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef ISC_RATELIMITER_H
+#define ISC_RATELIMITER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/ratelimiter.h
+ * \brief A rate limiter is a mechanism for dispatching events at a limited
+ * rate.  This is intended to be used when sending zone maintenance
+ * SOA queries, NOTIFY messages, etc.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Functions.
+ *****/
+
+isc_result_t
+isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
+                      isc_task_t *task, isc_ratelimiter_t **ratelimiterp);
+/*%<
+ * Create a rate limiter.  The execution interval is initially undefined.
+ */
+
+isc_result_t
+isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval);
+/*!<
+ * Set the minimum interval between event executions.
+ * The interval value is copied, so the caller need not preserve it.
+ *
+ * Requires:
+ *     '*interval' is a nonzero interval.
+ */
+
+void
+isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t perint);
+/*%<
+ * Set the number of events processed per interval timer tick.
+ * If 'perint' is zero it is treated as 1.
+ */
+
+isc_result_t
+isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
+                       isc_event_t **eventp);
+/*%<
+ * Queue an event for rate-limited execution.
+ *
+ * This is similar
+ * to doing an isc_task_send() to the 'task', except that the
+ * execution may be delayed to achieve the desired rate of
+ * execution.
+ *
+ * '(*eventp)->ev_sender' is used to hold the task.  The caller
+ * must ensure that the task exists until the event is delivered.
+ *
+ * Requires:
+ *\li  An interval has been set by calling
+ *     isc_ratelimiter_setinterval().
+ *
+ *\li  'task' to be non NULL.
+ *\li  '(*eventp)->ev_sender' to be NULL.
+ */
+
+void
+isc_ratelimiter_shutdown(isc_ratelimiter_t *ratelimiter);
+/*%<
+ * Shut down a rate limiter.
+ *
+ * Ensures:
+ *\li  All events that have not yet been
+ *     dispatched to the task are dispatched immediately with
+ *     the #ISC_EVENTATTR_CANCELED bit set in ev_attributes.
+ *
+ *\li  Further attempts to enqueue events will fail with
+ *     #ISC_R_SHUTTINGDOWN.
+ *
+ *\li  The rate limiter is no longer attached to its task.
+ */
+
+void
+isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target);
+/*%<
+ * Attach to a rate limiter.
+ */
+
+void
+isc_ratelimiter_detach(isc_ratelimiter_t **ratelimiterp);
+/*%<
+ * Detach from a rate limiter.
+ */
+
+isc_result_t
+isc_ratelimiter_stall(isc_ratelimiter_t *rl);
+/*%<
+ * Stall event processing.
+ */
+
+isc_result_t
+isc_ratelimiter_release(isc_ratelimiter_t *rl);
+/*%<
+ * Release a stalled rate limiter.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RATELIMITER_H */
diff --git a/lib/isc/include/isc/refcount.h b/lib/isc/include/isc/refcount.h
new file mode 100644 (file)
index 0000000..6ab14ae
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: refcount.h,v 1.15 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_REFCOUNT_H
+#define ISC_REFCOUNT_H 1
+
+#include <isc/atomic.h>
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+/*! \file isc/refcount.h
+ * \brief Implements a locked reference counter.  
+ *
+ * These functions may actually be
+ * implemented using macros, and implementations of these macros are below.
+ * The isc_refcount_t type should not be accessed directly, as its contents
+ * depend on the implementation.
+ */
+
+ISC_LANG_BEGINDECLS
+
+/*
+ * Function prototypes
+ */
+
+/* 
+ * isc_result_t
+ * isc_refcount_init(isc_refcount_t *ref, unsigned int n);
+ *
+ * Initialize the reference counter.  There will be 'n' initial references.
+ *
+ * Requires:
+ *     ref != NULL
+ */
+
+/*
+ * void
+ * isc_refcount_destroy(isc_refcount_t *ref);
+ *
+ * Destroys a reference counter.
+ *
+ * Requires:
+ *     ref != NULL
+ *     The number of references is 0.
+ */
+
+/*
+ * void
+ * isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp);
+ * isc_refcount_increment0(isc_refcount_t *ref, unsigned int *targetp);
+ *
+ * Increments the reference count, returning the new value in targetp if it's
+ * not NULL.  The reference counter typically begins with the initial counter
+ * of 1, and will be destroyed once the counter reaches 0.  Thus,
+ * isc_refcount_increment() additionally requires the previous counter be
+ * larger than 0 so that an error which violates the usage can be easily
+ * caught.  isc_refcount_increment0() does not have this restriction.
+ *
+ * Requires:
+ *     ref != NULL.
+ */
+
+/*
+ * void
+ * isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp);
+ *
+ * Decrements the reference count,  returning the new value in targetp if it's
+ * not NULL.
+ *
+ * Requires:
+ *     ref != NULL.
+ */
+
+
+/*
+ * Sample implementations
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+#ifdef ISC_PLATFORM_HAVEXADD
+
+#define ISC_REFCOUNT_HAVEATOMIC 1
+
+typedef struct isc_refcount {
+       isc_int32_t refs;
+} isc_refcount_t;
+
+#define isc_refcount_destroy(rp) (REQUIRE((rp)->refs == 0))
+#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
+
+#define isc_refcount_increment0(rp, tp)                                \
+       do {                                                    \
+               unsigned int *_tmp = (unsigned int *)(tp);      \
+               isc_int32_t prev;                               \
+               prev = isc_atomic_xadd(&(rp)->refs, 1);         \
+               if (_tmp != NULL)                               \
+                       *_tmp = prev + 1;                       \
+       } while (0)
+
+#define isc_refcount_increment(rp, tp)                         \
+       do {                                                    \
+               unsigned int *_tmp = (unsigned int *)(tp);      \
+               isc_int32_t prev;                               \
+               prev = isc_atomic_xadd(&(rp)->refs, 1);         \
+               REQUIRE(prev > 0);                              \
+               if (_tmp != NULL)                               \
+                       *_tmp = prev + 1;                       \
+       } while (0)
+
+#define isc_refcount_decrement(rp, tp)                         \
+       do {                                                    \
+               unsigned int *_tmp = (unsigned int *)(tp);      \
+               isc_int32_t prev;                               \
+               prev = isc_atomic_xadd(&(rp)->refs, -1);        \
+               REQUIRE(prev > 0);                              \
+               if (_tmp != NULL)                               \
+                       *_tmp = prev - 1;                       \
+       } while (0)
+
+#else  /* ISC_PLATFORM_HAVEXADD */
+
+typedef struct isc_refcount {
+       int refs;
+       isc_mutex_t lock;
+} isc_refcount_t;
+
+/*% Destroys a reference counter. */
+#define isc_refcount_destroy(rp)                       \
+       do {                                            \
+               REQUIRE((rp)->refs == 0);               \
+               DESTROYLOCK(&(rp)->lock);               \
+       } while (0)
+
+#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
+
+/*% Increments the reference count, returning the new value in targetp if it's not NULL. */
+#define isc_refcount_increment0(rp, tp)                                \
+       do {                                                    \
+               unsigned int *_tmp = (unsigned int *)(tp);      \
+               LOCK(&(rp)->lock);                              \
+               ++((rp)->refs);                                 \
+               if (_tmp != NULL)                               \
+                       *_tmp = ((rp)->refs);                   \
+               UNLOCK(&(rp)->lock);                            \
+       } while (0)
+
+#define isc_refcount_increment(rp, tp)                         \
+       do {                                                    \
+               unsigned int *_tmp = (unsigned int *)(tp);      \
+               LOCK(&(rp)->lock);                              \
+               REQUIRE((rp)->refs > 0);                        \
+               ++((rp)->refs);                                 \
+               if (_tmp != NULL)                               \
+                       *_tmp = ((rp)->refs);                   \
+               UNLOCK(&(rp)->lock);                            \
+       } while (0)
+
+/*% Decrements the reference count,  returning the new value in targetp if it's not NULL. */
+#define isc_refcount_decrement(rp, tp)                         \
+       do {                                                    \
+               unsigned int *_tmp = (unsigned int *)(tp);      \
+               LOCK(&(rp)->lock);                              \
+               REQUIRE((rp)->refs > 0);                        \
+               --((rp)->refs);                                 \
+               if (_tmp != NULL)                               \
+                       *_tmp = ((rp)->refs);                   \
+               UNLOCK(&(rp)->lock);                            \
+       } while (0)
+
+#endif /* ISC_PLATFORM_HAVEXADD */
+#else  /* ISC_PLATFORM_USETHREADS */
+
+typedef struct isc_refcount {
+       int refs;
+} isc_refcount_t;
+
+#define isc_refcount_destroy(rp) (REQUIRE((rp)->refs == 0))
+#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
+
+#define isc_refcount_increment0(rp, tp)                                        \
+       do {                                                            \
+               unsigned int *_tmp = (unsigned int *)(tp);              \
+               int _n = ++(rp)->refs;                                  \
+               if (_tmp != NULL)                                       \
+                       *_tmp = _n;                                     \
+       } while (0)
+
+#define isc_refcount_increment(rp, tp)                                 \
+       do {                                                            \
+               unsigned int *_tmp = (unsigned int *)(tp);              \
+               int _n;                                                 \
+               REQUIRE((rp)->refs > 0);                                \
+               _n = ++(rp)->refs;                                      \
+               if (_tmp != NULL)                                       \
+                       *_tmp = _n;                                     \
+       } while (0)
+
+#define isc_refcount_decrement(rp, tp)                                 \
+       do {                                                            \
+               unsigned int *_tmp = (unsigned int *)(tp);              \
+               int _n;                                                 \
+               REQUIRE((rp)->refs > 0);                                \
+               _n = --(rp)->refs;                                      \
+               if (_tmp != NULL)                                       \
+                       *_tmp = _n;                                     \
+       } while (0)
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_refcount_init(isc_refcount_t *ref, unsigned int n);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_REFCOUNT_H */
index 5622394aaf4378b42d47391e32bfb3fc73c1ca79..43d8f8f2d3e97ec4e48f4569d51f5e28cf31f3b0 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: region.h,v 1.16.12.3 2004/03/08 09:04:53 marka Exp $ */
+/* $Id: region.h,v 1.25 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_REGION_H
 #define ISC_REGION_H 1
 
+/*! \file isc/region.h */
+
 #include <isc/types.h>
 
 struct isc_region {
@@ -45,7 +47,8 @@ struct isc_consttextregion {
        unsigned int    length;
 };
 
-/*
+/*@{*/
+/*!
  * The region structure is not opaque, and is usually directly manipulated.
  * Some macros are defined below for convenience.
  */
@@ -76,20 +79,21 @@ struct isc_consttextregion {
                _r->base += _l; \
                _r->length -= _l; \
        } while (0)
+/*@}*/
 
 int
 isc_region_compare(isc_region_t *r1, isc_region_t *r2);
-/*
+/*%<
  * Compares the contents of two regions 
  *
  * Requires: 
- *     'r1' is a valid region
- *     'r2' is a valid region
+ *\li  'r1' is a valid region
+ *\li  'r2' is a valid region
  *
  * Returns:
- *      < 0 if r1 is lexicographically less than r2
- *      = 0 if r1 is lexicographically identical to r2
- *      > 0 if r1 is lexicographically greater than r2
+ *\li   < 0 if r1 is lexicographically less than r2
+ *\li   = 0 if r1 is lexicographically identical to r2
+ *\li   > 0 if r1 is lexicographically greater than r2
  */
 
 #endif /* ISC_REGION_H */
diff --git a/lib/isc/include/isc/resource.h b/lib/isc/include/isc/resource.h
new file mode 100644 (file)
index 0000000..747c9fd
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: resource.h,v 1.13 2008/07/11 23:47:09 tbox Exp $ */
+
+#ifndef ISC_RESOURCE_H
+#define ISC_RESOURCE_H 1
+
+/*! \file isc/resource.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_RESOURCE_UNLIMITED ((isc_resourcevalue_t)ISC_UINT64_MAX)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value);
+/*%<
+ * Set the maximum limit for a system resource.
+ *
+ * Notes:
+ *\li  If 'value' exceeds the maximum possible on the operating system,
+ *     it is silently limited to that maximum -- or to "infinity", if
+ *     the operating system has that concept.  #ISC_RESOURCE_UNLIMITED
+ *     can be used to explicitly ask for the maximum.
+ *
+ * Requires:
+ *\li  'resource' is a valid member of the isc_resource_t enumeration.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS  Success.
+ *\li  #ISC_R_NOTIMPLEMENTED   'resource' is not a type known by the OS.
+ *\li  #ISC_R_NOPERM   The calling process did not have adequate permission
+ *                     to change the resource limit.
+ */
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value);
+/*%<
+ * Get the maximum limit for a system resource.
+ *
+ * Notes:
+ *\li  'value' is set to the maximum limit.
+ *
+ *\li  #ISC_RESOURCE_UNLIMITED is the maximum value of isc_resourcevalue_t.
+ *
+ *\li  On many (all?) Unix systems, RLIM_INFINITY is a valid value that is
+ *     significantly less than #ISC_RESOURCE_UNLIMITED, but which in practice
+ *     behaves the same.
+ *
+ *\li  The current ISC libdns configuration file parser assigns a value
+ *     of ISC_UINT32_MAX for a size_spec of "unlimited" and ISC_UNIT32_MAX - 1
+ *     for "default", the latter of which is supposed to represent "the
+ *     limit that was in force when the server started".  Since these are
+ *     valid values in the middle of the range of isc_resourcevalue_t,
+ *     there is the possibility for confusion over what exactly those
+ *     particular values are supposed to represent in a particular context --
+ *     discrete integral values or generalized concepts.
+ *
+ * Requires:
+ *\li  'resource' is a valid member of the isc_resource_t enumeration.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS          Success.
+ *\li  #ISC_R_NOTIMPLEMENTED   'resource' is not a type known by the OS.
+ */
+
+isc_result_t
+isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value);
+/*%<
+ * Same as isc_resource_getlimit(), but returns the current (soft) limit.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS          Success.
+ *\li  #ISC_R_NOTIMPLEMENTED   'resource' is not a type known by the OS.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RESOURCE_H */
+
index 93f7cefbd658b4272813c122f8beb8d3049d5958..56b4ca6d691a837fc2086ea859a276a46c0f8757 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.h,v 1.57.2.2.8.5 2004/05/15 03:46:13 jinmei Exp $ */
+/* $Id: result.h,v 1.71 2008/09/25 04:02:39 tbox Exp $ */
 
 #ifndef ISC_RESULT_H
 #define ISC_RESULT_H 1
 
+/*! \file isc/result.h */
+
 #include <isc/lang.h>
 #include <isc/types.h>
 
-#define ISC_R_SUCCESS                  0       /* success */
-#define ISC_R_NOMEMORY                 1       /* out of memory */
-#define ISC_R_TIMEDOUT                 2       /* timed out */
-#define ISC_R_NOTHREADS                        3       /* no available threads */
-#define ISC_R_ADDRNOTAVAIL             4       /* address not available */
-#define ISC_R_ADDRINUSE                        5       /* address in use */
-#define ISC_R_NOPERM                   6       /* permission denied */
-#define ISC_R_NOCONN                   7       /* no pending connections */
-#define ISC_R_NETUNREACH               8       /* network unreachable */
-#define ISC_R_HOSTUNREACH              9       /* host unreachable */
-#define ISC_R_NETDOWN                  10      /* network down */
-#define ISC_R_HOSTDOWN                 11      /* host down */
-#define ISC_R_CONNREFUSED              12      /* connection refused */
-#define ISC_R_NORESOURCES              13      /* not enough free resources */
-#define ISC_R_EOF                      14      /* end of file */
-#define ISC_R_BOUND                    15      /* socket already bound */
-#define ISC_R_RELOAD                   16      /* reload */
-#define ISC_R_LOCKBUSY                 17      /* lock busy */
-#define ISC_R_EXISTS                   18      /* already exists */
-#define ISC_R_NOSPACE                  19      /* ran out of space */
-#define ISC_R_CANCELED                 20      /* operation canceled */
-#define ISC_R_NOTBOUND                 21      /* socket is not bound */
-#define ISC_R_SHUTTINGDOWN             22      /* shutting down */
-#define ISC_R_NOTFOUND                 23      /* not found */
-#define ISC_R_UNEXPECTEDEND            24      /* unexpected end of input */
-#define ISC_R_FAILURE                  25      /* generic failure */
-#define ISC_R_IOERROR                  26      /* I/O error */
-#define ISC_R_NOTIMPLEMENTED           27      /* not implemented */
-#define ISC_R_UNBALANCED               28      /* unbalanced parentheses */
-#define ISC_R_NOMORE                   29      /* no more */
-#define ISC_R_INVALIDFILE              30      /* invalid file */
-#define ISC_R_BADBASE64                        31      /* bad base64 encoding */
-#define ISC_R_UNEXPECTEDTOKEN          32      /* unexpected token */
-#define ISC_R_QUOTA                    33      /* quota reached */
-#define ISC_R_UNEXPECTED               34      /* unexpected error */
-#define ISC_R_ALREADYRUNNING           35      /* already running */
-#define ISC_R_IGNORE                   36      /* ignore */
-#define ISC_R_MASKNONCONTIG             37     /* addr mask not contiguous */
-#define ISC_R_FILENOTFOUND             38      /* file not found */
-#define ISC_R_FILEEXISTS               39      /* file already exists */
-#define ISC_R_NOTCONNECTED             40      /* socket is not connected */
-#define ISC_R_RANGE                    41      /* out of range */
-#define ISC_R_NOENTROPY                        42      /* out of entropy */
-#define ISC_R_MULTICAST                        43      /* invalid use of multicast */
-#define ISC_R_NOTFILE                  44      /* not a file */
-#define ISC_R_NOTDIRECTORY             45      /* not a directory */
-#define ISC_R_QUEUEFULL                        46      /* queue is full */
-#define ISC_R_FAMILYMISMATCH           47      /* address family mismatch */
-#define ISC_R_FAMILYNOSUPPORT          48      /* AF not supported */
-#define ISC_R_BADHEX                   49      /* bad hex encoding */
-#define ISC_R_TOOMANYOPENFILES         50      /* too many open files */
-#define ISC_R_NOTBLOCKING              51      /* not blocking */
-#define ISC_R_UNBALANCEDQUOTES         52      /* unbalanced quotes */
-#define ISC_R_INPROGRESS               53      /* operation in progress */
-#define ISC_R_CONNECTIONRESET          54      /* connection reset */
-#define ISC_R_SOFTQUOTA                        55      /* soft quota reached */
-#define ISC_R_BADNUMBER                        56      /* not a valid number */
-#define ISC_R_DISABLED                 57      /* disabled */
-#define ISC_R_MAXSIZE                  58      /* max size */
-#define ISC_R_BADADDRESSFORM           59      /* invalid address format */
+#define ISC_R_SUCCESS                  0       /*%< success */
+#define ISC_R_NOMEMORY                 1       /*%< out of memory */
+#define ISC_R_TIMEDOUT                 2       /*%< timed out */
+#define ISC_R_NOTHREADS                        3       /*%< no available threads */
+#define ISC_R_ADDRNOTAVAIL             4       /*%< address not available */
+#define ISC_R_ADDRINUSE                        5       /*%< address in use */
+#define ISC_R_NOPERM                   6       /*%< permission denied */
+#define ISC_R_NOCONN                   7       /*%< no pending connections */
+#define ISC_R_NETUNREACH               8       /*%< network unreachable */
+#define ISC_R_HOSTUNREACH              9       /*%< host unreachable */
+#define ISC_R_NETDOWN                  10      /*%< network down */
+#define ISC_R_HOSTDOWN                 11      /*%< host down */
+#define ISC_R_CONNREFUSED              12      /*%< connection refused */
+#define ISC_R_NORESOURCES              13      /*%< not enough free resources */
+#define ISC_R_EOF                      14      /*%< end of file */
+#define ISC_R_BOUND                    15      /*%< socket already bound */
+#define ISC_R_RELOAD                   16      /*%< reload */
+#define ISC_R_LOCKBUSY                 17      /*%< lock busy */
+#define ISC_R_EXISTS                   18      /*%< already exists */
+#define ISC_R_NOSPACE                  19      /*%< ran out of space */
+#define ISC_R_CANCELED                 20      /*%< operation canceled */
+#define ISC_R_NOTBOUND                 21      /*%< socket is not bound */
+#define ISC_R_SHUTTINGDOWN             22      /*%< shutting down */
+#define ISC_R_NOTFOUND                 23      /*%< not found */
+#define ISC_R_UNEXPECTEDEND            24      /*%< unexpected end of input */
+#define ISC_R_FAILURE                  25      /*%< generic failure */
+#define ISC_R_IOERROR                  26      /*%< I/O error */
+#define ISC_R_NOTIMPLEMENTED           27      /*%< not implemented */
+#define ISC_R_UNBALANCED               28      /*%< unbalanced parentheses */
+#define ISC_R_NOMORE                   29      /*%< no more */
+#define ISC_R_INVALIDFILE              30      /*%< invalid file */
+#define ISC_R_BADBASE64                        31      /*%< bad base64 encoding */
+#define ISC_R_UNEXPECTEDTOKEN          32      /*%< unexpected token */
+#define ISC_R_QUOTA                    33      /*%< quota reached */
+#define ISC_R_UNEXPECTED               34      /*%< unexpected error */
+#define ISC_R_ALREADYRUNNING           35      /*%< already running */
+#define ISC_R_IGNORE                   36      /*%< ignore */
+#define ISC_R_MASKNONCONTIG             37     /*%< addr mask not contiguous */
+#define ISC_R_FILENOTFOUND             38      /*%< file not found */
+#define ISC_R_FILEEXISTS               39      /*%< file already exists */
+#define ISC_R_NOTCONNECTED             40      /*%< socket is not connected */
+#define ISC_R_RANGE                    41      /*%< out of range */
+#define ISC_R_NOENTROPY                        42      /*%< out of entropy */
+#define ISC_R_MULTICAST                        43      /*%< invalid use of multicast */
+#define ISC_R_NOTFILE                  44      /*%< not a file */
+#define ISC_R_NOTDIRECTORY             45      /*%< not a directory */
+#define ISC_R_QUEUEFULL                        46      /*%< queue is full */
+#define ISC_R_FAMILYMISMATCH           47      /*%< address family mismatch */
+#define ISC_R_FAMILYNOSUPPORT          48      /*%< AF not supported */
+#define ISC_R_BADHEX                   49      /*%< bad hex encoding */
+#define ISC_R_TOOMANYOPENFILES         50      /*%< too many open files */
+#define ISC_R_NOTBLOCKING              51      /*%< not blocking */
+#define ISC_R_UNBALANCEDQUOTES         52      /*%< unbalanced quotes */
+#define ISC_R_INPROGRESS               53      /*%< operation in progress */
+#define ISC_R_CONNECTIONRESET          54      /*%< connection reset */
+#define ISC_R_SOFTQUOTA                        55      /*%< soft quota reached */
+#define ISC_R_BADNUMBER                        56      /*%< not a valid number */
+#define ISC_R_DISABLED                 57      /*%< disabled */
+#define ISC_R_MAXSIZE                  58      /*%< max size */
+#define ISC_R_BADADDRESSFORM           59      /*%< invalid address format */
+#define ISC_R_BADBASE32                        60      /*%< bad base32 encoding */
 
-/*
- * Not a result code: the number of results.
- */
-#define ISC_R_NRESULTS                         60
+/*% Not a result code: the number of results. */
+#define ISC_R_NRESULTS                         61
 
 ISC_LANG_BEGINDECLS
 
 const char *
 isc_result_totext(isc_result_t);
-/*
+/*%<
  * Convert an isc_result_t into a string message describing the result.
  */
 
diff --git a/lib/isc/include/isc/resultclass.h b/lib/isc/include/isc/resultclass.h
new file mode 100644 (file)
index 0000000..b32426f
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: resultclass.h,v 1.18 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_RESULTCLASS_H
+#define ISC_RESULTCLASS_H 1
+
+
+/*! \file isc/resultclass.h
+ * \brief Registry of Predefined Result Type Classes
+ *
+ * A result class number is an unsigned 16 bit number.  Each class may
+ * contain up to 65536 results.  A result code is formed by adding the
+ * result number within the class to the class number multiplied by 65536.
+ *
+ * Classes < 1024 are reserved for ISC use.
+ * Result classes >= 1024 and <= 65535 are reserved for application use.
+ */
+
+#define ISC_RESULTCLASS_FROMNUM(num)           ((num) << 16)
+#define ISC_RESULTCLASS_TONUM(rclass)          ((rclass) >> 16)
+#define ISC_RESULTCLASS_SIZE                   65536
+#define ISC_RESULTCLASS_INCLASS(rclass, result) \
+       ((rclass) == ((result) & 0xFFFF0000))
+
+
+#define        ISC_RESULTCLASS_ISC             ISC_RESULTCLASS_FROMNUM(0)
+#define        ISC_RESULTCLASS_DNS             ISC_RESULTCLASS_FROMNUM(1)
+#define        ISC_RESULTCLASS_DST             ISC_RESULTCLASS_FROMNUM(2)
+#define        ISC_RESULTCLASS_DNSRCODE        ISC_RESULTCLASS_FROMNUM(3)
+#define        ISC_RESULTCLASS_OMAPI           ISC_RESULTCLASS_FROMNUM(4)
+#define        ISC_RESULTCLASS_ISCCC           ISC_RESULTCLASS_FROMNUM(5)
+
+
+#endif /* ISC_RESULTCLASS_H */
diff --git a/lib/isc/include/isc/rwlock.h b/lib/isc/include/isc/rwlock.h
new file mode 100644 (file)
index 0000000..28052cd
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: rwlock.h,v 1.28 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_RWLOCK_H
+#define ISC_RWLOCK_H 1
+
+/*! \file isc/rwlock.h */
+
+#include <isc/condition.h>
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef enum {
+       isc_rwlocktype_none = 0,
+       isc_rwlocktype_read,
+       isc_rwlocktype_write
+} isc_rwlocktype_t;
+
+#ifdef ISC_PLATFORM_USETHREADS
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+#define ISC_RWLOCK_USEATOMIC 1
+#endif
+
+struct isc_rwlock {
+       /* Unlocked. */
+       unsigned int            magic;
+       isc_mutex_t             lock;
+
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+       /*
+        * When some atomic instructions with hardware assistance are
+        * available, rwlock will use those so that concurrent readers do not
+        * interfere with each other through mutex as long as no writers
+        * appear, massively reducing the lock overhead in the typical case.
+        *
+        * The basic algorithm of this approach is the "simple
+        * writer-preference lock" shown in the following URL:
+        * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
+        * but our implementation does not rely on the spin lock unlike the
+        * original algorithm to be more portable as a user space application.
+        */
+
+       /* Read or modified atomically. */
+       isc_int32_t             write_requests;
+       isc_int32_t             write_completions;
+       isc_int32_t             cnt_and_flag;
+
+       /* Locked by lock. */
+       isc_condition_t         readable;
+       isc_condition_t         writeable;
+       unsigned int            readers_waiting;
+
+       /* Locked by rwlock itself. */
+       unsigned int            write_granted;
+
+       /* Unlocked. */
+       unsigned int            write_quota;
+
+#else  /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+
+       /*%< Locked by lock. */
+       isc_condition_t         readable;
+       isc_condition_t         writeable;
+       isc_rwlocktype_t        type;
+
+       /*% The number of threads that have the lock. */
+       unsigned int            active;
+
+       /*%
+        * The number of lock grants made since the lock was last switched
+        * from reading to writing or vice versa; used in determining
+        * when the quota is reached and it is time to switch.
+        */
+       unsigned int            granted;
+       
+       unsigned int            readers_waiting;
+       unsigned int            writers_waiting;
+       unsigned int            read_quota;
+       unsigned int            write_quota;
+       isc_rwlocktype_t        original;
+#endif  /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+};
+#else /* ISC_PLATFORM_USETHREADS */
+struct isc_rwlock {
+       unsigned int            magic;
+       isc_rwlocktype_t        type;
+       unsigned int            active;
+};
+#endif /* ISC_PLATFORM_USETHREADS */
+
+
+isc_result_t
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+               unsigned int write_quota);
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl);
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl);
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_RWLOCK_H */
diff --git a/lib/isc/include/isc/serial.h b/lib/isc/include/isc/serial.h
new file mode 100644 (file)
index 0000000..f7e3049
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: serial.h,v 1.16.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef ISC_SERIAL_H
+#define ISC_SERIAL_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file isc/serial.h
+ *     \brief Implement 32 bit serial space arithmetic comparison functions.
+ *     Note: Undefined results are returned as ISC_FALSE.
+ */
+
+/***
+ ***   Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_boolean_t
+isc_serial_lt(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ *     Return true if 'a' < 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_gt(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ *     Return true if 'a' > 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_le(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ *     Return true if 'a' <= 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_ge(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ *     Return true if 'a' >= 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_eq(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ *     Return true if 'a' == 'b' otherwise false.
+ */
+
+isc_boolean_t
+isc_serial_ne(isc_uint32_t a, isc_uint32_t b);
+/*%<
+ *     Return true if 'a' != 'b' otherwise false.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SERIAL_H */
diff --git a/lib/isc/include/isc/sha1.h b/lib/isc/include/isc/sha1.h
new file mode 100644 (file)
index 0000000..63f12bb
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ISC_SHA1_H
+#define ISC_SHA1_H 1
+
+/* $Id: sha1.h,v 1.17 2007/06/19 23:47:18 tbox Exp $ */
+
+/*     $NetBSD: sha1.h,v 1.2 1998/05/29 22:55:44 thorpej Exp $ */
+
+/*! \file isc/sha1.h
+ * \brief SHA-1 in C
+ * \author By Steve Reid <steve@edmweb.com>
+ * \note 100% Public Domain
+ */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_SHA1_DIGESTLENGTH 20U
+#define ISC_SHA1_BLOCK_LENGTH 64U
+
+typedef struct {
+       isc_uint32_t state[5];
+       isc_uint32_t count[2];
+       unsigned char buffer[ISC_SHA1_BLOCK_LENGTH];
+} isc_sha1_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_sha1_init(isc_sha1_t *ctx);
+
+void
+isc_sha1_invalidate(isc_sha1_t *ctx);
+
+void
+isc_sha1_update(isc_sha1_t *ctx, const unsigned char *data, unsigned int len);
+
+void
+isc_sha1_final(isc_sha1_t *ctx, unsigned char *digest);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SHA1_H */
diff --git a/lib/isc/include/isc/sha2.h b/lib/isc/include/isc/sha2.h
new file mode 100644 (file)
index 0000000..203600f
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2005-2007  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sha2.h,v 1.9 2007/06/19 23:47:18 tbox Exp $ */
+
+/*     $FreeBSD: src/sys/crypto/sha2/sha2.h,v 1.1.2.1 2001/07/03 11:01:36 ume Exp $    */
+/*     $KAME: sha2.h,v 1.3 2001/03/12 08:27:48 itojun Exp $    */
+
+/*
+ * sha2.h
+ *
+ * Version 1.0.0beta1
+ *
+ * Written by Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright 2000 Aaron D. Gifford.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef ISC_SHA2_H
+#define ISC_SHA2_H
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*** SHA-224/256/384/512 Various Length Definitions ***********************/
+
+#define ISC_SHA224_BLOCK_LENGTH                64U
+#define ISC_SHA224_DIGESTLENGTH        28U
+#define ISC_SHA224_DIGESTSTRINGLENGTH  (ISC_SHA224_DIGESTLENGTH * 2 + 1)
+#define ISC_SHA256_BLOCK_LENGTH                64U
+#define ISC_SHA256_DIGESTLENGTH        32U
+#define ISC_SHA256_DIGESTSTRINGLENGTH  (ISC_SHA256_DIGESTLENGTH * 2 + 1)
+#define ISC_SHA384_BLOCK_LENGTH                128
+#define ISC_SHA384_DIGESTLENGTH        48U
+#define ISC_SHA384_DIGESTSTRINGLENGTH  (ISC_SHA384_DIGESTLENGTH * 2 + 1)
+#define ISC_SHA512_BLOCK_LENGTH                128U
+#define ISC_SHA512_DIGESTLENGTH        64U
+#define ISC_SHA512_DIGESTSTRINGLENGTH  (ISC_SHA512_DIGESTLENGTH * 2 + 1)
+
+
+ISC_LANG_BEGINDECLS
+
+/*** SHA-256/384/512 Context Structures *******************************/
+
+/*
+ * Keep buffer immediately after bitcount to preserve alignment.
+ */
+typedef struct {
+       isc_uint32_t    state[8];
+       isc_uint64_t    bitcount;
+       isc_uint8_t     buffer[ISC_SHA256_BLOCK_LENGTH];
+} isc_sha256_t;
+
+/*
+ * Keep buffer immediately after bitcount to preserve alignment.
+ */
+typedef struct {
+       isc_uint64_t    state[8];
+       isc_uint64_t    bitcount[2];
+       isc_uint8_t     buffer[ISC_SHA512_BLOCK_LENGTH];
+} isc_sha512_t;
+
+typedef isc_sha256_t isc_sha224_t;
+typedef isc_sha512_t isc_sha384_t;
+
+/*** SHA-224/256/384/512 Function Prototypes ******************************/
+
+void isc_sha224_init (isc_sha224_t *);
+void isc_sha224_update (isc_sha224_t *, const isc_uint8_t *, size_t);
+void isc_sha224_final (isc_uint8_t[ISC_SHA224_DIGESTLENGTH], isc_sha224_t *);
+char *isc_sha224_end (isc_sha224_t *, char[ISC_SHA224_DIGESTSTRINGLENGTH]);
+char *isc_sha224_data (const isc_uint8_t *, size_t, char[ISC_SHA224_DIGESTSTRINGLENGTH]);
+
+void isc_sha256_init (isc_sha256_t *);
+void isc_sha256_update (isc_sha256_t *, const isc_uint8_t *, size_t);
+void isc_sha256_final (isc_uint8_t[ISC_SHA256_DIGESTLENGTH], isc_sha256_t *);
+char *isc_sha256_end (isc_sha256_t *, char[ISC_SHA256_DIGESTSTRINGLENGTH]);
+char *isc_sha256_data (const isc_uint8_t *, size_t, char[ISC_SHA256_DIGESTSTRINGLENGTH]);
+
+void isc_sha384_init (isc_sha384_t *);
+void isc_sha384_update (isc_sha384_t *, const isc_uint8_t *, size_t);
+void isc_sha384_final (isc_uint8_t[ISC_SHA384_DIGESTLENGTH], isc_sha384_t *);
+char *isc_sha384_end (isc_sha384_t *, char[ISC_SHA384_DIGESTSTRINGLENGTH]);
+char *isc_sha384_data (const isc_uint8_t *, size_t, char[ISC_SHA384_DIGESTSTRINGLENGTH]);
+
+void isc_sha512_init (isc_sha512_t *);
+void isc_sha512_update (isc_sha512_t *, const isc_uint8_t *, size_t);
+void isc_sha512_final (isc_uint8_t[ISC_SHA512_DIGESTLENGTH], isc_sha512_t *);
+char *isc_sha512_end (isc_sha512_t *, char[ISC_SHA512_DIGESTSTRINGLENGTH]);
+char *isc_sha512_data (const isc_uint8_t *, size_t, char[ISC_SHA512_DIGESTSTRINGLENGTH]);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SHA2_H */
index 635af38117bf5d4061893a03740809bc34a16a01..62cc77397a09dccf13df172610095f24434aa6ee 100644 (file)
@@ -1,34 +1,42 @@
 /*
- * Copyright (C) 1998-2002  Internet Software Consortium.
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: sockaddr.h,v 1.39 2002/04/03 06:38:36 marka Exp $ */
+/* $Id: sockaddr.h,v 1.55.332.2 2009/01/18 23:47:41 tbox Exp $ */
 
 #ifndef ISC_SOCKADDR_H
 #define ISC_SOCKADDR_H 1
 
+/*! \file isc/sockaddr.h */
+
 #include <isc/lang.h>
 #include <isc/net.h>
 #include <isc/types.h>
+#ifdef ISC_PLATFORM_HAVESYSUNH
+#include <sys/un.h>
+#endif
 
 struct isc_sockaddr {
        union {
                struct sockaddr         sa;
                struct sockaddr_in      sin;
                struct sockaddr_in6     sin6;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+               struct sockaddr_un      sunix;
+#endif
        }                               type;
        unsigned int                    length;         /* XXXRTH beginning? */
        ISC_LINK(struct isc_sockaddr)   link;
@@ -36,17 +44,36 @@ struct isc_sockaddr {
 
 typedef ISC_LIST(struct isc_sockaddr)  isc_sockaddrlist_t;
 
+#define ISC_SOCKADDR_CMPADDR     0x0001        /*%< compare the address
+                                                *   sin_addr/sin6_addr */
+#define ISC_SOCKADDR_CMPPORT     0x0002        /*%< compare the port
+                                                *   sin_port/sin6_port */
+#define ISC_SOCKADDR_CMPSCOPE     0x0004       /*%< compare the scope
+                                                *   sin6_scope */
+#define ISC_SOCKADDR_CMPSCOPEZERO 0x0008       /*%< when comparing scopes
+                                                *   zero scopes always match */
+
 ISC_LANG_BEGINDECLS
 
+isc_boolean_t
+isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+                    unsigned int flags);
+/*%<
+ * Compare the elements of the two address ('a' and 'b') as specified
+ * by 'flags' and report if they are equal or not.
+ *
+ * 'flags' is set from ISC_SOCKADDR_CMP*.
+ */
+
 isc_boolean_t
 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b);
-/*
+/*%<
  * Return ISC_TRUE iff the socket addresses 'a' and 'b' are equal.
  */
 
 isc_boolean_t
 isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b);
-/*
+/*%<
  * Return ISC_TRUE iff the address parts of the socket addresses
  * 'a' and 'b' are equal, ignoring the ports.
  */
@@ -54,14 +81,15 @@ isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b);
 isc_boolean_t
 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
                          unsigned int prefixlen);
-/*
+/*%<
  * Return ISC_TRUE iff the most significant 'prefixlen' bits of the
  * socket addresses 'a' and 'b' are equal, ignoring the ports.
+ * If 'b''s scope is zero then 'a''s scope will be ignored.
  */
 
 unsigned int
 isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only);
-/*
+/*%<
  * Return a hash value for the socket address 'sockaddr'.  If 'address_only'
  * is ISC_TRUE, the hash value will not depend on the port.
  *
@@ -71,129 +99,140 @@ isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only);
 
 void
 isc_sockaddr_any(isc_sockaddr_t *sockaddr);
-/*
+/*%<
  * Return the IPv4 wildcard address.
  */
 
 void
 isc_sockaddr_any6(isc_sockaddr_t *sockaddr);
-/*
+/*%<
  * Return the IPv6 wildcard address.
  */
 
 void
 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int family);
-/*
+/*%<
  * Set '*sockaddr' to the wildcard address of protocol family
  * 'family'.
  *
  * Requires:
- *     'family' is AF_INET or AF_INET6.
+ * \li 'family' is AF_INET or AF_INET6.
  */
 
 void
 isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
                    in_port_t port);
-/*
+/*%<
  * Construct an isc_sockaddr_t from an IPv4 address and port.
  */
 
 void
 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
                     in_port_t port);
-/*
+/*%<
  * Construct an isc_sockaddr_t from an IPv6 address and port.
  */
 
 void
 isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
                      in_port_t port);
-/*
+/*%<
  * Construct an IPv6 isc_sockaddr_t representing a mapped IPv4 address.
  */
 
 void
 isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
                         in_port_t port);
-/*
+/*%<
  * Construct an isc_sockaddr_t from an isc_netaddr_t and port.
  */
 
 int
 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr);
-/*
+/*%<
  * Get the protocol family of 'sockaddr'.
  *
  * Requires:
  *
- *     'sockaddr' is a valid sockaddr with an address family of AF_INET
+ *\li  'sockaddr' is a valid sockaddr with an address family of AF_INET
  *     or AF_INET6.
  *
  * Returns:
  *
- *     The protocol family of 'sockaddr', e.g. PF_INET or PF_INET6.
+ *\li  The protocol family of 'sockaddr', e.g. PF_INET or PF_INET6.
  */
 
 void
 isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port);
-/*
+/*%<
  * Set the port of 'sockaddr' to 'port'.
  */
 
 in_port_t
-isc_sockaddr_getport(isc_sockaddr_t *sockaddr);
-/*
+isc_sockaddr_getport(const isc_sockaddr_t *sockaddr);
+/*%<
  * Get the port stored in 'sockaddr'.
  */
 
 isc_result_t
 isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target);
-/*
+/*%<
  * Append a text representation of 'sockaddr' to the buffer 'target'.
  * The text will include both the IP address (v4 or v6) and the port.
  * The text is null terminated, but the terminating null is not
  * part of the buffer's used region.
  *
  * Returns:
- *     ISC_R_SUCCESS
- *     ISC_R_NOSPACE   The text or the null termination did not fit.
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOSPACE   The text or the null termination did not fit.
  */
 
 void
 isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size);
-/*
+/*%<
  * Format a human-readable representation of the socket address '*sa'
  * into the character array 'array', which is of size 'size'.
  * The resulting string is guaranteed to be null-terminated.
  */
 
 isc_boolean_t
-isc_sockaddr_ismulticast(isc_sockaddr_t *sa);
-/*
- * Returns ISC_TRUE if the address is a multicast address.
+isc_sockaddr_ismulticast(const isc_sockaddr_t *sa);
+/*%<
+ * Returns #ISC_TRUE if the address is a multicast address.
  */
 
 isc_boolean_t
-isc_sockaddr_isexperimental(isc_sockaddr_t *sa);
+isc_sockaddr_isexperimental(const isc_sockaddr_t *sa);
 /*
  * Returns ISC_TRUE if the address is a experimental (CLASS E) address.
  */
 
 isc_boolean_t
-isc_sockaddr_islinklocal(isc_sockaddr_t *sa);
-/*
- * Returns ISC_TRUE if the address is a link local addresss.
+isc_sockaddr_islinklocal(const isc_sockaddr_t *sa);
+/*%<
+ * Returns ISC_TRUE if the address is a link local address.
  */
 
 isc_boolean_t
-isc_sockaddr_issitelocal(isc_sockaddr_t *sa);
-/*
+isc_sockaddr_issitelocal(const isc_sockaddr_t *sa);
+/*%<
  * Returns ISC_TRUE if the address is a sitelocal address.
  */
 
-#define ISC_SOCKADDR_FORMATSIZE \
-       sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX#YYYYY")
+isc_result_t
+isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path);
 /*
+ *  Create a UNIX domain sockaddr that refers to path.
+ *
+ * Returns:
+ * \li ISC_R_NOSPACE
+ * \li ISC_R_NOTIMPLEMENTED
+ * \li ISC_R_SUCCESS
+ */
+
+#define ISC_SOCKADDR_FORMATSIZE \
+       sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS#YYYYY")
+/*%<
  * Minimum size of array to pass to isc_sockaddr_format().
  */
 
diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h
new file mode 100644 (file)
index 0000000..035c994
--- /dev/null
@@ -0,0 +1,1007 @@
+/*
+ * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: socket.h,v 1.85.58.3 2009/01/29 22:40:35 jinmei Exp $ */
+
+#ifndef ISC_SOCKET_H
+#define ISC_SOCKET_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/socket.h
+ * \brief Provides TCP and UDP sockets for network I/O.  The sockets are event
+ * sources in the task system.
+ *
+ * When I/O completes, a completion event for the socket is posted to the
+ * event queue of the task which requested the I/O.
+ *
+ * \li MP:
+ *     The module ensures appropriate synchronization of data structures it
+ *     creates and manipulates.
+ *     Clients of this module must not be holding a socket's task's lock when
+ *     making a call that affects that socket.  Failure to follow this rule
+ *     can result in deadlock.
+ *     The caller must ensure that isc_socketmgr_destroy() is called only
+ *     once for a given manager.
+ *
+ * \li Reliability:
+ *     No anticipated impact.
+ *
+ * \li Resources:
+ *     TBS
+ *
+ * \li Security:
+ *     No anticipated impact.
+ *
+ * \li Standards:
+ *     None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/time.h>
+#include <isc/region.h>
+#include <isc/sockaddr.h>
+#include <isc/xml.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Constants
+ ***/
+
+/*%
+ * Maximum number of buffers in a scatter/gather read/write.  The operating
+ * system in use must support at least this number (plus one on some.)
+ */
+#define ISC_SOCKET_MAXSCATTERGATHER    8
+
+/*%
+ * In isc_socket_bind() set socket option SO_REUSEADDR prior to calling
+ * bind() if a non zero port is specified (AF_INET and AF_INET6).
+ */
+#define ISC_SOCKET_REUSEADDRESS                0x01U
+
+/*%
+ * Statistics counters.  Used as isc_statscounter_t values.
+ */
+enum {
+       isc_sockstatscounter_udp4open = 0,
+       isc_sockstatscounter_udp6open = 1,
+       isc_sockstatscounter_tcp4open = 2,
+       isc_sockstatscounter_tcp6open = 3,
+       isc_sockstatscounter_unixopen = 4,
+
+       isc_sockstatscounter_udp4openfail = 5,
+       isc_sockstatscounter_udp6openfail = 6,
+       isc_sockstatscounter_tcp4openfail = 7,
+       isc_sockstatscounter_tcp6openfail = 8,
+       isc_sockstatscounter_unixopenfail = 9,
+
+       isc_sockstatscounter_udp4close = 10,
+       isc_sockstatscounter_udp6close = 11,
+       isc_sockstatscounter_tcp4close = 12,
+       isc_sockstatscounter_tcp6close = 13,
+       isc_sockstatscounter_unixclose = 14,
+       isc_sockstatscounter_fdwatchclose = 15,
+
+       isc_sockstatscounter_udp4bindfail = 16,
+       isc_sockstatscounter_udp6bindfail = 17,
+       isc_sockstatscounter_tcp4bindfail = 18,
+       isc_sockstatscounter_tcp6bindfail = 19,
+       isc_sockstatscounter_unixbindfail = 20,
+       isc_sockstatscounter_fdwatchbindfail = 21,
+
+       isc_sockstatscounter_udp4connect = 22,
+       isc_sockstatscounter_udp6connect = 23,
+       isc_sockstatscounter_tcp4connect = 24,
+       isc_sockstatscounter_tcp6connect = 25,
+       isc_sockstatscounter_unixconnect = 26,
+       isc_sockstatscounter_fdwatchconnect = 27,
+
+       isc_sockstatscounter_udp4connectfail = 28,
+       isc_sockstatscounter_udp6connectfail = 29,
+       isc_sockstatscounter_tcp4connectfail = 30,
+       isc_sockstatscounter_tcp6connectfail = 31,
+       isc_sockstatscounter_unixconnectfail = 32,
+       isc_sockstatscounter_fdwatchconnectfail = 33,
+
+       isc_sockstatscounter_tcp4accept = 34,
+       isc_sockstatscounter_tcp6accept = 35,
+       isc_sockstatscounter_unixaccept = 36,
+
+       isc_sockstatscounter_tcp4acceptfail = 37,
+       isc_sockstatscounter_tcp6acceptfail = 38,
+       isc_sockstatscounter_unixacceptfail = 39,
+
+       isc_sockstatscounter_udp4sendfail = 40,
+       isc_sockstatscounter_udp6sendfail = 41,
+       isc_sockstatscounter_tcp4sendfail = 42,
+       isc_sockstatscounter_tcp6sendfail = 43,
+       isc_sockstatscounter_unixsendfail = 44,
+       isc_sockstatscounter_fdwatchsendfail = 45,
+
+       isc_sockstatscounter_udp4recvfail = 46,
+       isc_sockstatscounter_udp6recvfail = 47,
+       isc_sockstatscounter_tcp4recvfail = 48,
+       isc_sockstatscounter_tcp6recvfail = 49,
+       isc_sockstatscounter_unixrecvfail = 50,
+       isc_sockstatscounter_fdwatchrecvfail = 51,
+
+       isc_sockstatscounter_max = 52
+};
+
+/***
+ *** Types
+ ***/
+
+struct isc_socketevent {
+       ISC_EVENT_COMMON(isc_socketevent_t);
+       isc_result_t            result;         /*%< OK, EOF, whatever else */
+       unsigned int            minimum;        /*%< minimum i/o for event */
+       unsigned int            n;              /*%< bytes read or written */
+       unsigned int            offset;         /*%< offset into buffer list */
+       isc_region_t            region;         /*%< for single-buffer i/o */
+       isc_bufferlist_t        bufferlist;     /*%< list of buffers */
+       isc_sockaddr_t          address;        /*%< source address */
+       isc_time_t              timestamp;      /*%< timestamp of packet recv */
+       struct in6_pktinfo      pktinfo;        /*%< ipv6 pktinfo */
+       isc_uint32_t            attributes;     /*%< see below */
+       isc_eventdestructor_t   destroy;        /*%< original destructor */
+};
+
+typedef struct isc_socket_newconnev isc_socket_newconnev_t;
+struct isc_socket_newconnev {
+       ISC_EVENT_COMMON(isc_socket_newconnev_t);
+       isc_socket_t *          newsocket;
+       isc_result_t            result;         /*%< OK, EOF, whatever else */
+       isc_sockaddr_t          address;        /*%< source address */
+};
+
+typedef struct isc_socket_connev isc_socket_connev_t;
+struct isc_socket_connev {
+       ISC_EVENT_COMMON(isc_socket_connev_t);
+       isc_result_t            result;         /*%< OK, EOF, whatever else */
+};
+
+/*@{*/
+/*!
+ * _ATTACHED:  Internal use only.
+ * _TRUNC:     Packet was truncated on receive.
+ * _CTRUNC:    Packet control information was truncated.  This can
+ *             indicate that the packet is not complete, even though
+ *             all the data is valid.
+ * _TIMESTAMP: The timestamp member is valid.
+ * _PKTINFO:   The pktinfo member is valid.
+ * _MULTICAST: The UDP packet was received via a multicast transmission.
+ */
+#define ISC_SOCKEVENTATTR_ATTACHED             0x80000000U /* internal */
+#define ISC_SOCKEVENTATTR_TRUNC                        0x00800000U /* public */
+#define ISC_SOCKEVENTATTR_CTRUNC               0x00400000U /* public */
+#define ISC_SOCKEVENTATTR_TIMESTAMP            0x00200000U /* public */
+#define ISC_SOCKEVENTATTR_PKTINFO              0x00100000U /* public */
+#define ISC_SOCKEVENTATTR_MULTICAST            0x00080000U /* public */
+/*@}*/
+
+#define ISC_SOCKEVENT_ANYEVENT  (0)
+#define ISC_SOCKEVENT_RECVDONE (ISC_EVENTCLASS_SOCKET + 1)
+#define ISC_SOCKEVENT_SENDDONE (ISC_EVENTCLASS_SOCKET + 2)
+#define ISC_SOCKEVENT_NEWCONN  (ISC_EVENTCLASS_SOCKET + 3)
+#define ISC_SOCKEVENT_CONNECT  (ISC_EVENTCLASS_SOCKET + 4)
+
+/*
+ * Internal events.
+ */
+#define ISC_SOCKEVENT_INTR     (ISC_EVENTCLASS_SOCKET + 256)
+#define ISC_SOCKEVENT_INTW     (ISC_EVENTCLASS_SOCKET + 257)
+
+typedef enum {
+       isc_sockettype_udp = 1,
+       isc_sockettype_tcp = 2,
+       isc_sockettype_unix = 3,
+       isc_sockettype_fdwatch = 4
+} isc_sockettype_t;
+
+/*@{*/
+/*!
+ * How a socket should be shutdown in isc_socket_shutdown() calls.
+ */
+#define ISC_SOCKSHUT_RECV      0x00000001      /*%< close read side */
+#define ISC_SOCKSHUT_SEND      0x00000002      /*%< close write side */
+#define ISC_SOCKSHUT_ALL       0x00000003      /*%< close them all */
+/*@}*/
+
+/*@{*/
+/*!
+ * What I/O events to cancel in isc_socket_cancel() calls.
+ */
+#define ISC_SOCKCANCEL_RECV    0x00000001      /*%< cancel recv */
+#define ISC_SOCKCANCEL_SEND    0x00000002      /*%< cancel send */
+#define ISC_SOCKCANCEL_ACCEPT  0x00000004      /*%< cancel accept */
+#define ISC_SOCKCANCEL_CONNECT 0x00000008      /*%< cancel connect */
+#define ISC_SOCKCANCEL_ALL     0x0000000f      /*%< cancel everything */
+/*@}*/
+
+/*@{*/
+/*!
+ * Flags for isc_socket_send() and isc_socket_recv() calls.
+ */
+#define ISC_SOCKFLAG_IMMEDIATE 0x00000001      /*%< send event only if needed */
+#define ISC_SOCKFLAG_NORETRY   0x00000002      /*%< drop failed UDP sends */
+/*@}*/
+
+/*@{*/
+/*!
+ * Flags for fdwatchcreate.
+ */
+#define ISC_SOCKFDWATCH_READ   0x00000001      /*%< watch for readable */
+#define ISC_SOCKFDWATCH_WRITE  0x00000002      /*%< watch for writable */
+/*@}*/
+
+/***
+ *** Socket and Socket Manager Functions
+ ***
+ *** Note: all Ensures conditions apply only if the result is success for
+ *** those functions which return an isc_result.
+ ***/
+
+isc_result_t
+isc_socket_fdwatchcreate(isc_socketmgr_t *manager,
+                        int fd,
+                        int flags,
+                        isc_sockfdwatch_t callback,
+                        void *cbarg,
+                        isc_task_t *task,
+                        isc_socket_t **socketp);
+/*%<
+ * Create a new file descriptor watch socket managed by 'manager'.
+ *
+ * Note:
+ *
+ *\li   'fd' is the already-opened file descriptor.
+ *\li  This function is not available on Windows.
+ *\li  The callback function is called "in-line" - this means the function
+ *     needs to return as fast as possible, as all other I/O will be suspended
+ *     until the callback completes.
+ *
+ * Requires:
+ *
+ *\li  'manager' is a valid manager
+ *
+ *\li  'socketp' is a valid pointer, and *socketp == NULL
+ *
+ *\li  'fd' be opened.
+ *
+ * Ensures:
+ *
+ *     '*socketp' is attached to the newly created fdwatch socket
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_NORESOURCES
+ *\li  #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_create(isc_socketmgr_t *manager,
+                 int pf,
+                 isc_sockettype_t type,
+                 isc_socket_t **socketp);
+/*%<
+ * Create a new 'type' socket managed by 'manager'.
+ *
+ * For isc_sockettype_fdwatch sockets you should use isc_socket_fdwatchcreate()
+ * rather than isc_socket_create().
+ *
+ * Note:
+ *
+ *\li  'pf' is the desired protocol family, e.g. PF_INET or PF_INET6.
+ *
+ * Requires:
+ *
+ *\li  'manager' is a valid manager
+ *
+ *\li  'socketp' is a valid pointer, and *socketp == NULL
+ *
+ *\li  'type' is not isc_sockettype_fdwatch
+ *
+ * Ensures:
+ *
+ *     '*socketp' is attached to the newly created socket
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_NORESOURCES
+ *\li  #ISC_R_UNEXPECTED
+ */
+
+void
+isc_socket_cancel(isc_socket_t *sock, isc_task_t *task,
+                 unsigned int how);
+/*%<
+ * Cancel pending I/O of the type specified by "how".
+ *
+ * Note: if "task" is NULL, then the cancel applies to all tasks using the
+ * socket.
+ *
+ * Requires:
+ *
+ * \li "socket" is a valid socket
+ *
+ * \li "task" is NULL or a valid task
+ *
+ * "how" is a bitmask describing the type of cancelation to perform.
+ * The type ISC_SOCKCANCEL_ALL will cancel all pending I/O on this
+ * socket.
+ *
+ * \li ISC_SOCKCANCEL_RECV:
+ *     Cancel pending isc_socket_recv() calls.
+ *
+ * \li ISC_SOCKCANCEL_SEND:
+ *     Cancel pending isc_socket_send() and isc_socket_sendto() calls.
+ *
+ * \li ISC_SOCKCANCEL_ACCEPT:
+ *     Cancel pending isc_socket_accept() calls.
+ *
+ * \li ISC_SOCKCANCEL_CONNECT:
+ *     Cancel pending isc_socket_connect() call.
+ */
+
+void
+isc_socket_shutdown(isc_socket_t *sock, unsigned int how);
+/*%<
+ * Shutdown 'socket' according to 'how'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket.
+ *
+ * \li 'task' is NULL or is a valid task.
+ *
+ * \li If 'how' is 'ISC_SOCKSHUT_RECV' or 'ISC_SOCKSHUT_ALL' then
+ *
+ *             The read queue must be empty.
+ *
+ *             No further read requests may be made.
+ *
+ * \li If 'how' is 'ISC_SOCKSHUT_SEND' or 'ISC_SOCKSHUT_ALL' then
+ *
+ *             The write queue must be empty.
+ *
+ *             No further write requests may be made.
+ */
+
+void
+isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp);
+/*%<
+ * Attach *socketp to socket.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket.
+ *
+ * \li 'socketp' points to a NULL socket.
+ *
+ * Ensures:
+ *
+ * \li *socketp is attached to socket.
+ */
+
+void
+isc_socket_detach(isc_socket_t **socketp);
+/*%<
+ * Detach *socketp from its socket.
+ *
+ * Requires:
+ *
+ * \li 'socketp' points to a valid socket.
+ *
+ * \li If '*socketp' is the last reference to the socket,
+ *     then:
+ *
+ *             There must be no pending I/O requests.
+ *
+ * Ensures:
+ *
+ * \li *socketp is NULL.
+ *
+ * \li If '*socketp' is the last reference to the socket,
+ *     then:
+ *
+ *             The socket will be shutdown (both reading and writing)
+ *             for all tasks.
+ *
+ *             All resources used by the socket have been freed
+ */
+
+isc_result_t
+isc_socket_open(isc_socket_t *sock);
+/*%<
+ * Open a new socket file descriptor of the given socket structure.  It simply
+ * opens a new descriptor; all of the other parameters including the socket
+ * type are inherited from the existing socket.  This function is provided to
+ * avoid overhead of destroying and creating sockets when many short-lived
+ * sockets are frequently opened and closed.  When the efficiency is not an
+ * issue, it should be safer to detach the unused socket and re-create a new
+ * one.  This optimization may not be available for some systems, in which
+ * case this function will return ISC_R_NOTIMPLEMENTED and must not be used.
+ *
+ * isc_socket_open() should not be called on sockets created by
+ * isc_socket_fdwatchcreate().
+ *
+ * Requires:
+ *
+ * \li there must be no other reference to this socket.
+ *
+ * \li 'socket' is a valid and previously closed by isc_socket_close()
+ *
+ * \li  'sock->type' is not isc_sockettype_fdwatch
+ *
+ * Returns:
+ *     Same as isc_socket_create().
+ * \li ISC_R_NOTIMPLEMENTED
+ */
+
+isc_result_t
+isc_socket_close(isc_socket_t *sock);
+/*%<
+ * Close a socket file descriptor of the given socket structure.  This function
+ * is provided as an alternative to destroying an unused socket when overhead
+ * destroying/re-creating sockets can be significant, and is expected to be
+ * used with isc_socket_open().  This optimization may not be available for some
+ * systems, in which case this function will return ISC_R_NOTIMPLEMENTED and
+ * must not be used.
+ *
+ * isc_socket_close() should not be called on sockets created by
+ * isc_socket_fdwatchcreate().
+ *
+ * Requires:
+ *
+ * \li The socket must have a valid descriptor.
+ *
+ * \li There must be no other reference to this socket.
+ *
+ * \li There must be no pending I/O requests.
+ *
+ * \li  'sock->type' is not isc_sockettype_fdwatch
+ *
+ * Returns:
+ * \li #ISC_R_NOTIMPLEMENTED
+ */
+
+isc_result_t
+isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *addressp,
+               unsigned int options);
+/*%<
+ * Bind 'socket' to '*addressp'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket
+ *
+ * \li 'addressp' points to a valid isc_sockaddr.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOPERM
+ * \li ISC_R_ADDRNOTAVAIL
+ * \li ISC_R_ADDRINUSE
+ * \li ISC_R_BOUND
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_filter(isc_socket_t *sock, const char *filter);
+/*%<
+ * Inform the kernel that it should perform accept filtering.
+ * If filter is NULL the current filter will be removed.:w
+ */
+
+isc_result_t
+isc_socket_listen(isc_socket_t *sock, unsigned int backlog);
+/*%<
+ * Set listen mode on the socket.  After this call, the only function that
+ * can be used (other than attach and detach) is isc_socket_accept().
+ *
+ * Notes:
+ *
+ * \li 'backlog' is as in the UNIX system call listen() and may be
+ *     ignored by non-UNIX implementations.
+ *
+ * \li If 'backlog' is zero, a reasonable system default is used, usually
+ *     SOMAXCONN.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid, bound TCP socket or a valid, bound UNIX socket.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_accept(isc_socket_t *sock,
+                 isc_task_t *task, isc_taskaction_t action, const void *arg);
+/*%<
+ * Queue accept event.  When a new connection is received, the task will
+ * get an ISC_SOCKEVENT_NEWCONN event with the sender set to the listen
+ * socket.  The new socket structure is sent inside the isc_socket_newconnev_t
+ * event type, and is attached to the task 'task'.
+ *
+ * REQUIRES:
+ * \li 'socket' is a valid TCP socket that isc_socket_listen() was called
+ *     on.
+ *
+ * \li 'task' is a valid task
+ *
+ * \li 'action' is a valid action
+ *
+ * RETURNS:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addressp,
+                  isc_task_t *task, isc_taskaction_t action,
+                  const void *arg);
+/*%<
+ * Connect 'socket' to peer with address *saddr.  When the connection
+ * succeeds, or when an error occurs, a CONNECT event with action 'action'
+ * and arg 'arg' will be posted to the event queue for 'task'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid TCP socket
+ *
+ * \li 'addressp' points to a valid isc_sockaddr
+ *
+ * \li 'task' is a valid task
+ *
+ * \li 'action' is a valid action
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_UNEXPECTED
+ *
+ * Posted event's result code:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_TIMEDOUT
+ * \li ISC_R_CONNREFUSED
+ * \li ISC_R_NETUNREACH
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp);
+/*%<
+ * Get the name of the peer connected to 'socket'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid TCP socket.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_TOOSMALL
+ * \li ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp);
+/*%<
+ * Get the name of 'socket'.
+ *
+ * Requires:
+ *
+ * \li 'socket' is a valid socket.
+ *
+ * Returns:
+ *
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_TOOSMALL
+ * \li ISC_R_UNEXPECTED
+ */
+
+/*@{*/
+isc_result_t
+isc_socket_recv(isc_socket_t *sock, isc_region_t *region,
+               unsigned int minimum,
+               isc_task_t *task, isc_taskaction_t action, const void *arg);
+isc_result_t
+isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+                unsigned int minimum,
+                isc_task_t *task, isc_taskaction_t action, const void *arg);
+
+isc_result_t
+isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
+                unsigned int minimum, isc_task_t *task,
+                isc_socketevent_t *event, unsigned int flags);
+
+/*!
+ * Receive from 'socket', storing the results in region.
+ *
+ * Notes:
+ *
+ *\li  Let 'length' refer to the length of 'region' or to the sum of all
+ *     available regions in the list of buffers '*buflist'.
+ *
+ *\li  If 'minimum' is non-zero and at least that many bytes are read,
+ *     the completion event will be posted to the task 'task.'  If minimum
+ *     is zero, the exact number of bytes requested in the region must
+ *     be read for an event to be posted.  This only makes sense for TCP
+ *     connections, and is always set to 1 byte for UDP.
+ *
+ *\li  The read will complete when the desired number of bytes have been
+ *     read, if end-of-input occurs, or if an error occurs.  A read done
+ *     event with the given 'action' and 'arg' will be posted to the
+ *     event queue of 'task'.
+ *
+ *\li  The caller may not modify 'region', the buffers which are passed
+ *     into this function, or any data they refer to until the completion
+ *     event is received.
+ *
+ *\li  For isc_socket_recvv():
+ *     On successful completion, '*buflist' will be empty, and the list of
+ *     all buffers will be returned in the done event's 'bufferlist'
+ *     member.  On error return, '*buflist' will be unchanged.
+ *
+ *\li  For isc_socket_recv2():
+ *     'event' is not NULL, and the non-socket specific fields are
+ *     expected to be initialized.
+ *
+ *\li  For isc_socket_recv2():
+ *     The only defined value for 'flags' is ISC_SOCKFLAG_IMMEDIATE.  If
+ *     set and the operation completes, the return value will be
+ *     ISC_R_SUCCESS and the event will be filled in and not sent.  If the
+ *     operation does not complete, the return value will be
+ *     ISC_R_INPROGRESS and the event will be sent when the operation
+ *     completes.
+ *
+ * Requires:
+ *
+ *\li  'socket' is a valid, bound socket.
+ *
+ *\li  For isc_socket_recv():
+ *     'region' is a valid region
+ *
+ *\li  For isc_socket_recvv():
+ *     'buflist' is non-NULL, and '*buflist' contain at least one buffer.
+ *
+ *\li  'task' is a valid task
+ *
+ *\li  For isc_socket_recv() and isc_socket_recvv():
+ *     action != NULL and is a valid action
+ *
+ *\li  For isc_socket_recv2():
+ *     event != NULL
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_INPROGRESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_UNEXPECTED
+ *
+ * Event results:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_UNEXPECTED
+ *\li  XXX needs other net-type errors
+ */
+/*@}*/
+
+/*@{*/
+isc_result_t
+isc_socket_send(isc_socket_t *sock, isc_region_t *region,
+               isc_task_t *task, isc_taskaction_t action, const void *arg);
+isc_result_t
+isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
+                 isc_task_t *task, isc_taskaction_t action, const void *arg,
+                 isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
+isc_result_t
+isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+                isc_task_t *task, isc_taskaction_t action, const void *arg);
+isc_result_t
+isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+                  isc_task_t *task, isc_taskaction_t action, const void *arg,
+                  isc_sockaddr_t *address, struct in6_pktinfo *pktinfo);
+isc_result_t
+isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+                  isc_task_t *task,
+                  isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+                  isc_socketevent_t *event, unsigned int flags);
+
+/*!
+ * Send the contents of 'region' to the socket's peer.
+ *
+ * Notes:
+ *
+ *\li  Shutting down the requestor's task *may* result in any
+ *     still pending writes being dropped or completed, depending on the
+ *     underlying OS implementation.
+ *
+ *\li  If 'action' is NULL, then no completion event will be posted.
+ *
+ *\li  The caller may not modify 'region', the buffers which are passed
+ *     into this function, or any data they refer to until the completion
+ *     event is received.
+ *
+ *\li  For isc_socket_sendv() and isc_socket_sendtov():
+ *     On successful completion, '*buflist' will be empty, and the list of
+ *     all buffers will be returned in the done event's 'bufferlist'
+ *     member.  On error return, '*buflist' will be unchanged.
+ *
+ *\li  For isc_socket_sendto2():
+ *     'event' is not NULL, and the non-socket specific fields are
+ *     expected to be initialized.
+ *
+ *\li  For isc_socket_sendto2():
+ *     The only defined values for 'flags' are ISC_SOCKFLAG_IMMEDIATE
+ *     and ISC_SOCKFLAG_NORETRY.
+ *
+ *\li  If ISC_SOCKFLAG_IMMEDIATE is set and the operation completes, the
+ *     return value will be ISC_R_SUCCESS and the event will be filled
+ *     in and not sent.  If the operation does not complete, the return
+ *     value will be ISC_R_INPROGRESS and the event will be sent when
+ *     the operation completes.
+ *
+ *\li  ISC_SOCKFLAG_NORETRY can only be set for UDP sockets.  If set
+ *     and the send operation fails due to a transient error, the send
+ *     will not be retried and the error will be indicated in the event.
+ *     Using this option along with ISC_SOCKFLAG_IMMEDIATE allows the caller
+ *     to specify a region that is allocated on the stack.
+ *
+ * Requires:
+ *
+ *\li  'socket' is a valid, bound socket.
+ *
+ *\li  For isc_socket_send():
+ *     'region' is a valid region
+ *
+ *\li  For isc_socket_sendv() and isc_socket_sendtov():
+ *     'buflist' is non-NULL, and '*buflist' contain at least one buffer.
+ *
+ *\li  'task' is a valid task
+ *
+ *\li  For isc_socket_sendv(), isc_socket_sendtov(), isc_socket_send(), and
+ *     isc_socket_sendto():
+ *     action == NULL or is a valid action
+ *
+ *\li  For isc_socket_sendto2():
+ *     event != NULL
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_INPROGRESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_UNEXPECTED
+ *
+ * Event results:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_UNEXPECTED
+ *\li  XXX needs other net-type errors
+ */
+/*@}*/
+
+isc_result_t
+isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp);
+
+isc_result_t
+isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
+                     unsigned int maxsocks);
+/*%<
+ * Create a socket manager.  If "maxsocks" is non-zero, it specifies the
+ * maximum number of sockets that the created manager should handle.
+ * isc_socketmgr_create() is equivalent of isc_socketmgr_create2() with
+ * "maxsocks" being zero.
+ *
+ * Notes:
+ *
+ *\li  All memory will be allocated in memory context 'mctx'.
+ *
+ * Requires:
+ *
+ *\li  'mctx' is a valid memory context.
+ *
+ *\li  'managerp' points to a NULL isc_socketmgr_t.
+ *
+ * Ensures:
+ *
+ *\li  '*managerp' is a valid isc_socketmgr_t.
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_UNEXPECTED
+ *\li  #ISC_R_NOTIMPLEMENTED
+ */
+
+isc_result_t
+isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp);
+/*%<
+ * Returns in "*nsockp" the maximum number of sockets this manager may open.
+ *
+ * Requires:
+ *
+ *\li  '*manager' is a valid isc_socketmgr_t.
+ *\li  'nsockp' is not NULL.
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOTIMPLEMENTED
+ */
+
+void
+isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats);
+/*%<
+ * Set a general socket statistics counter set 'stats' for 'manager'.
+ *
+ * Requires:
+ * \li 'manager' is valid, hasn't opened any socket, and doesn't have
+ *     stats already set.
+ *
+ *\li  stats is a valid statistics supporting socket statistics counters
+ *     (see above).
+ */
+
+void
+isc_socketmgr_destroy(isc_socketmgr_t **managerp);
+/*%<
+ * Destroy a socket manager.
+ *
+ * Notes:
+ *
+ *\li  This routine blocks until there are no sockets left in the manager,
+ *     so if the caller holds any socket references using the manager, it
+ *     must detach them before calling isc_socketmgr_destroy() or it will
+ *     block forever.
+ *
+ * Requires:
+ *
+ *\li  '*managerp' is a valid isc_socketmgr_t.
+ *
+ *\li  All sockets managed by this manager are fully detached.
+ *
+ * Ensures:
+ *
+ *\li  *managerp == NULL
+ *
+ *\li  All resources used by the manager have been freed.
+ */
+
+isc_sockettype_t
+isc_socket_gettype(isc_socket_t *sock);
+/*%<
+ * Returns the socket type for "sock."
+ *
+ * Requires:
+ *
+ *\li  "sock" is a valid socket.
+ */
+
+/*@{*/
+isc_boolean_t
+isc_socket_isbound(isc_socket_t *sock);
+
+void
+isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes);
+/*%<
+ * If the socket is an IPv6 socket set/clear the IPV6_IPV6ONLY socket
+ * option if the host OS supports this option.
+ *
+ * Requires:
+ *\li  'sock' is a valid socket.
+ */
+/*@}*/
+
+void
+isc_socket_cleanunix(isc_sockaddr_t *addr, isc_boolean_t active);
+
+/*%<
+ * Cleanup UNIX domain sockets in the file-system.  If 'active' is true
+ * then just unlink the socket.  If 'active' is false try to determine
+ * if there is a listener of the socket or not.  If no listener is found
+ * then unlink socket.
+ *
+ * Prior to unlinking the path is tested to see if it a socket.
+ *
+ * Note: there are a number of race conditions which cannot be avoided
+ *       both in the filesystem and any application using UNIX domain
+ *      sockets (e.g. socket is tested between bind() and listen(),
+ *      the socket is deleted and replaced in the file-system between
+ *      stat() and unlink()).
+ */
+
+isc_result_t
+isc_socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm,
+                   isc_uint32_t owner, isc_uint32_t group);
+/*%<
+ * Set ownership and file permissions on the UNIX domain socket.
+ *
+ * Note: On Solaris and SunOS this secures the directory containing
+ *       the socket as Solaris and SunOS do not honour the filesystem
+ *      permissions on the socket.
+ *
+ * Requires:
+ * \li 'sockaddr' to be a valid UNIX domain sockaddr.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_FAILURE
+ */
+
+void isc_socket_setname(isc_socket_t *socket, const char *name, void *tag);
+/*%<
+ * Set the name and optional tag for a socket.  This allows tracking of the
+ * owner or purpose for this socket, and is useful for tracing and statistics
+ * reporting.
+ */
+
+const char *isc_socket_getname(isc_socket_t *socket);
+/*%<
+ * Get the name associated with a socket, if any.
+ */
+
+void *isc_socket_gettag(isc_socket_t *socket);
+/*%<
+ * Get the tag associated with a socket, if any.
+ */
+
+void
+isc__socketmgr_setreserved(isc_socketmgr_t *mgr, isc_uint32_t);
+/*%<
+ * Temporary.  For use by named only.
+ */
+
+#ifdef HAVE_LIBXML2
+
+void
+isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer);
+/*%<
+ * Render internal statistics and other state into the XML document.
+ */
+
+#endif /* HAVE_LIBXML2 */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SOCKET_H */
diff --git a/lib/isc/include/isc/stats.h b/lib/isc/include/isc/stats.h
new file mode 100644 (file)
index 0000000..a6156d8
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stats.h,v 1.4.2.2 2009/01/29 23:47:44 tbox Exp $ */
+
+#ifndef ISC_STATS_H
+#define ISC_STATS_H 1
+
+/*! \file isc/stats.h */
+
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%<
+ * Flag(s) for isc_stats_dump().
+ */
+#define ISC_STATSDUMP_VERBOSE  0x00000001 /*%< dump 0-value counters */
+
+/*%<
+ * Dump callback type.
+ */
+typedef void (*isc_stats_dumper_t)(isc_statscounter_t, isc_uint64_t, void *);
+
+isc_result_t
+isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters);
+/*%<
+ * Create a statistics counter structure of general type.  It counts a general
+ * set of counters indexed by an ID between 0 and ncounters -1.
+ *
+ * Requires:
+ *\li  'mctx' must be a valid memory context.
+ *
+ *\li  'statsp' != NULL && '*statsp' == NULL.
+ *
+ * Returns:
+ *\li  ISC_R_SUCCESS   -- all ok
+ *
+ *\li  anything else   -- failure
+ */
+
+void
+isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp);
+/*%<
+ * Attach to a statistics set.
+ *
+ * Requires:
+ *\li  'stats' is a valid isc_stats_t.
+ *
+ *\li  'statsp' != NULL && '*statsp' == NULL
+ */
+
+void
+isc_stats_detach(isc_stats_t **statsp);
+/*%<
+ * Detaches from the statistics set.
+ *
+ * Requires:
+ *\li  'statsp' != NULL and '*statsp' is a valid isc_stats_t.
+ */
+
+int
+isc_stats_ncounters(isc_stats_t *stats);
+/*%<
+ * Returns the number of counters contained in stats.
+ *
+ * Requires:
+ *\li  'stats' is a valid isc_stats_t.
+ *
+ */
+
+void
+isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter);
+/*%<
+ * Increment the counter-th counter of stats.
+ *
+ * Requires:
+ *\li  'stats' is a valid isc_stats_t.
+ *
+ *\li  counter is less than the maximum available ID for the stats specified
+ *     on creation.
+ */
+
+void
+isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter);
+/*%<
+ * Decrement the counter-th counter of stats.
+ *
+ * Requires:
+ *\li  'stats' is a valid isc_stats_t.
+ */
+
+void
+isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn, void *arg,
+              unsigned int options);
+/*%<
+ * Dump the current statistics counters in a specified way.  For each counter
+ * in stats, dump_fn is called with its current value and the given argument
+ * arg.  By default counters that have a value of 0 is skipped; if options has
+ * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped.
+ *
+ * Requires:
+ *\li  'stats' is a valid isc_stats_t.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STATS_H */
index e3bf0cd3ecabe415a4fbc388ea006f962095dd48..1a7ae642d5eba2e8903dbf39ad304e460003e129 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2000, 2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: stdio.h,v 1.7.18.2 2005/04/29 00:17:03 marka Exp $ */
+/* $Id: stdio.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_STDIO_H
 #define ISC_STDIO_H 1
 
-/*! \file */
+/*! \file isc/stdio.h */
 
 /*% 
  * These functions are wrappers around the corresponding stdio functions.
diff --git a/lib/isc/include/isc/stdlib.h b/lib/isc/include/isc/stdlib.h
new file mode 100644 (file)
index 0000000..02243f0
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stdlib.h,v 1.8 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_STDLIB_H
+#define ISC_STDLIB_H 1
+
+/*! \file isc/stdlib.h */
+
+#include <stdlib.h>
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+
+#ifdef ISC_PLATFORM_NEEDSTRTOUL
+#define strtoul isc_strtoul
+#endif
+
+ISC_LANG_BEGINDECLS
+
+unsigned long isc_strtoul(const char *, char **, int);
+
+ISC_LANG_ENDDECLS
+
+#endif
index e16219fdaad0c32bebccb7a223f1beb5c2827635..b49fdbc327f15ee4a07f56d620f1ceb98f1a86ea 100644 (file)
@@ -1,36 +1,46 @@
 /*
- * Copyright (C) 2000, 2001  Internet Software Consortium.
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: string.h,v 1.9 2001/01/09 21:57:37 bwelling Exp $ */
+/* $Id: string.h,v 1.23 2007/09/13 04:48:16 each Exp $ */
 
 #ifndef ISC_STRING_H
 #define ISC_STRING_H 1
 
-#include <string.h>
+/*! \file isc/string.h */
 
+#include <isc/formatcheck.h>
 #include <isc/int.h>
 #include <isc/lang.h>
 #include <isc/platform.h>
+#include <isc/types.h>
+
+#include <string.h>
+
+#ifdef ISC_PLATFORM_HAVESTRINGSH
+#include <strings.h>
+#endif
+
+#define ISC_STRING_MAGIC 0x5e
 
 ISC_LANG_BEGINDECLS
 
 isc_uint64_t
 isc_string_touint64(char *source, char **endp, int base);
-/*
+/*%<
  * Convert the string pointed to by 'source' to isc_uint64_t.
  *
  * On successful conversion 'endp' points to the first character
@@ -43,6 +53,151 @@ isc_string_touint64(char *source, char **endp, int base);
  * On error 'endp' points to 'source'.
  */
 
+isc_result_t
+isc_string_copy(char *target, size_t size, const char *source);
+/*
+ * Copy the string pointed to by 'source' to 'target' which is a
+ * pointer to a string of at least 'size' bytes.
+ *
+ * Requires:
+ *     'target' is a pointer to a char[] of at least 'size' bytes.
+ *     'size' an integer > 0.
+ *     'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ *     If result == ISC_R_SUCCESS
+ *             'target' will be a NUL terminated string of no more
+ *             than 'size' bytes (including NUL).
+ *
+ *     If result == ISC_R_NOSPACE
+ *             'target' is undefined.
+ *
+ * Returns:
+ *     ISC_R_SUCCESS  -- 'source' was successfully copied to 'target'.
+ *     ISC_R_NOSPACE  -- 'source' could not be copied since 'target'
+ *                       is too small.
+ */
+
+void
+isc_string_copy_truncate(char *target, size_t size, const char *source);
+/*
+ * Copy the string pointed to by 'source' to 'target' which is a
+ * pointer to a string of at least 'size' bytes.
+ *
+ * Requires:
+ *     'target' is a pointer to a char[] of at least 'size' bytes.
+ *     'size' an integer > 0.
+ *     'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ *     'target' will be a NUL terminated string of no more
+ *     than 'size' bytes (including NUL).
+ */
+
+isc_result_t
+isc_string_append(char *target, size_t size, const char *source);
+/*
+ * Append the string pointed to by 'source' to 'target' which is a
+ * pointer to a NUL terminated string of at least 'size' bytes.
+ *
+ * Requires:
+ *     'target' is a pointer to a NUL terminated char[] of at
+ *     least 'size' bytes.
+ *     'size' an integer > 0.
+ *     'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ *     If result == ISC_R_SUCCESS
+ *             'target' will be a NUL terminated string of no more
+ *             than 'size' bytes (including NUL).
+ *
+ *     If result == ISC_R_NOSPACE
+ *             'target' is undefined.
+ *
+ * Returns:
+ *     ISC_R_SUCCESS  -- 'source' was successfully appended to 'target'.
+ *     ISC_R_NOSPACE  -- 'source' could not be appended since 'target'
+ *                       is too small.
+ */
+
+void
+isc_string_append_truncate(char *target, size_t size, const char *source);
+/*
+ * Append the string pointed to by 'source' to 'target' which is a
+ * pointer to a NUL terminated string of at least 'size' bytes.
+ *
+ * Requires:
+ *     'target' is a pointer to a NUL terminated char[] of at
+ *     least 'size' bytes.
+ *     'size' an integer > 0.
+ *     'source' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ *     'target' will be a NUL terminated string of no more
+ *     than 'size' bytes (including NUL).
+ */
+
+isc_result_t
+isc_string_printf(char *target, size_t size, const char *format, ...)
+       ISC_FORMAT_PRINTF(3, 4);
+/*
+ * Print 'format' to 'target' which is a pointer to a string of at least
+ * 'size' bytes.
+ *
+ * Requires:
+ *     'target' is a pointer to a char[] of at least 'size' bytes.
+ *     'size' an integer > 0.
+ *     'format' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ *     If result == ISC_R_SUCCESS
+ *             'target' will be a NUL terminated string of no more
+ *             than 'size' bytes (including NUL).
+ *
+ *     If result == ISC_R_NOSPACE
+ *             'target' is undefined.
+ *
+ * Returns:
+ *     ISC_R_SUCCESS  -- 'format' was successfully printed to 'target'.
+ *     ISC_R_NOSPACE  -- 'format' could not be printed to 'target' since it
+ *                       is too small.
+ */
+
+void
+isc_string_printf_truncate(char *target, size_t size, const char *format, ...)
+       ISC_FORMAT_PRINTF(3, 4);
+/*
+ * Print 'format' to 'target' which is a pointer to a string of at least
+ * 'size' bytes.
+ *
+ * Requires:
+ *     'target' is a pointer to a char[] of at least 'size' bytes.
+ *     'size' an integer > 0.
+ *     'format' == NULL or points to a NUL terminated string.
+ *
+ * Ensures:
+ *     'target' will be a NUL terminated string of no more
+ *     than 'size' bytes (including NUL).
+ */
+
+
+char *
+isc_string_regiondup(isc_mem_t *mctx, const isc_region_t *source);
+/*
+ * Copy the region pointed to by r to a NUL terminated string
+ * allocated from the memory context pointed to by mctx.
+ *
+ * The result should be deallocated using isc_mem_free()
+ *
+ * Requires:
+ *     'mctx' is a point to a valid memory context.
+ *     'source' is a pointer to a valid region.
+ *
+ * Returns:
+ *     a pointer to a NUL terminated string or
+ *     NULL if memory for the copy could not be allocated
+ *
+ */
 
 char *
 isc_string_separate(char **stringp, const char *delim);
@@ -51,6 +206,26 @@ isc_string_separate(char **stringp, const char *delim);
 #define strsep isc_string_separate
 #endif
 
+#ifdef ISC_PLATFORM_NEEDMEMMOVE
+#define memmove(a,b,c) bcopy(b,a,c)
+#endif
+
+size_t
+isc_string_strlcpy(char *dst, const char *src, size_t size);
+
+
+#ifdef ISC_PLATFORM_NEEDSTRLCPY
+#define strlcpy isc_string_strlcpy
+#endif
+
+
+size_t
+isc_string_strlcat(char *dst, const char *src, size_t size);
+
+#ifdef ISC_PLATFORM_NEEDSTRLCAT
+#define strlcat isc_string_strlcat
+#endif
+
 ISC_LANG_ENDDECLS
 
 #endif /* ISC_STRING_H */
diff --git a/lib/isc/include/isc/symtab.h b/lib/isc/include/isc/symtab.h
new file mode 100644 (file)
index 0000000..396d645
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: symtab.h,v 1.24.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef ISC_SYMTAB_H
+#define ISC_SYMTAB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/symtab.h
+ * \brief Provides a simple memory-based symbol table.
+ *
+ * Keys are C strings, and key comparisons are case-insensitive.  A type may
+ * be specified when looking up, defining, or undefining.  A type value of
+ * 0 means "match any type"; any other value will only match the given
+ * type.
+ *
+ * It's possible that a client will attempt to define a <key, type, value>
+ * tuple when a tuple with the given key and type already exists in the table.
+ * What to do in this case is specified by the client.  Possible policies are:
+ *
+ *\li  #isc_symexists_reject   Disallow the define, returning #ISC_R_EXISTS
+ *\li  #isc_symexists_replace  Replace the old value with the new.  The
+ *                             undefine action (if provided) will be called
+ *                             with the old <key, type, value> tuple.
+ *\li  #isc_symexists_add      Add the new tuple, leaving the old tuple in
+ *                             the table.  Subsequent lookups will retrieve
+ *                             the most-recently-defined tuple.
+ *
+ * A lookup of a key using type 0 will return the most-recently defined
+ * symbol with that key.  An undefine of a key using type 0 will undefine the
+ * most-recently defined symbol with that key.  Trying to define a key with
+ * type 0 is illegal.
+ *
+ * The symbol table library does not make a copy the key field, so the
+ * caller must ensure that any key it passes to isc_symtab_define() will not
+ * change until it calls isc_symtab_undefine() or isc_symtab_destroy().
+ *
+ * A user-specified action will be called (if provided) when a symbol is
+ * undefined.  It can be used to free memory associated with keys and/or
+ * values.
+ *
+ * \li MP:
+ *     The callers of this module must ensure any required synchronization.
+ *
+ * \li Reliability:
+ *     No anticipated impact.
+ *
+ * \li Resources:
+ *     TBS
+ *
+ * \li Security:
+ *     No anticipated impact.
+ *
+ * \li Standards:
+ *     None.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*
+ *** Symbol Tables.
+ ***/
+/*% Symbol table value. */
+typedef union isc_symvalue {
+       void *                          as_pointer;
+       const void *                    as_cpointer;
+       int                             as_integer;
+       unsigned int                    as_uinteger;
+} isc_symvalue_t;
+
+typedef void (*isc_symtabaction_t)(char *key, unsigned int type,
+                                  isc_symvalue_t value, void *userarg);
+/*% Symbol table exists. */
+typedef enum {
+       isc_symexists_reject = 0,       /*%< Disallow the define */
+       isc_symexists_replace = 1,      /*%< Replace the old value with the new */
+       isc_symexists_add = 2           /*%< Add the new tuple */
+} isc_symexists_t;
+
+ISC_LANG_BEGINDECLS
+
+/*% Create a symbol table. */
+isc_result_t
+isc_symtab_create(isc_mem_t *mctx, unsigned int size,
+                 isc_symtabaction_t undefine_action, void *undefine_arg,
+                 isc_boolean_t case_sensitive, isc_symtab_t **symtabp);
+
+/*% Destroy a symbol table. */
+void
+isc_symtab_destroy(isc_symtab_t **symtabp);
+
+/*% Lookup a symbol table. */
+isc_result_t
+isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
+                 isc_symvalue_t *value);
+
+/*% Define a symbol table. */
+isc_result_t
+isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
+                 isc_symvalue_t value, isc_symexists_t exists_policy);
+
+/*% Undefine a symbol table. */
+isc_result_t
+isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SYMTAB_H */
diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h
new file mode 100644 (file)
index 0000000..8106571
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: task.h,v 1.61.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef ISC_TASK_H
+#define ISC_TASK_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/task.h
+ * \brief The task system provides a lightweight execution context, which is
+ * basically an event queue.
+
+ * When a task's event queue is non-empty, the
+ * task is runnable.  A small work crew of threads, typically one per CPU,
+ * execute runnable tasks by dispatching the events on the tasks' event
+ * queues.  Context switching between tasks is fast.
+ *
+ * \li MP:
+ *     The module ensures appropriate synchronization of data structures it
+ *     creates and manipulates.
+ *     The caller must ensure that isc_taskmgr_destroy() is called only
+ *     once for a given manager.
+ *
+ * \li Reliability:
+ *     No anticipated impact.
+ *
+ * \li Resources:
+ *     TBS
+ *
+ * \li Security:
+ *     No anticipated impact.
+ *
+ * \li Standards:
+ *     None.
+ *
+ * \section purge Purging and Unsending
+ *
+ * Events which have been queued for a task but not delivered may be removed
+ * from the task's event queue by purging or unsending.
+ *
+ * With both types, the caller specifies a matching pattern that selects
+ * events based upon their sender, type, and tag.
+ *
+ * Purging calls isc_event_free() on the matching events.
+ *
+ * Unsending returns a list of events that matched the pattern.
+ * The caller is then responsible for them.
+ *
+ * Consumers of events should purge, not unsend.
+ *
+ * Producers of events often want to remove events when the caller indicates
+ * it is no longer interested in the object, e.g. by canceling a timer.
+ * Sometimes this can be done by purging, but for some event types, the
+ * calls to isc_event_free() cause deadlock because the event free routine
+ * wants to acquire a lock the caller is already holding.  Unsending instead
+ * of purging solves this problem.  As a general rule, producers should only
+ * unsend events which they have sent.
+ */
+
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/stdtime.h>
+#include <isc/types.h>
+#include <isc/xml.h>
+
+#define ISC_TASKEVENT_FIRSTEVENT       (ISC_EVENTCLASS_TASK + 0)
+#define ISC_TASKEVENT_SHUTDOWN         (ISC_EVENTCLASS_TASK + 1)
+#define ISC_TASKEVENT_LASTEVENT                (ISC_EVENTCLASS_TASK + 65535)
+
+/*****
+ ***** Tasks.
+ *****/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
+               isc_task_t **taskp);
+/*%<
+ * Create a task.
+ *
+ * Notes:
+ *
+ *\li  If 'quantum' is non-zero, then only that many events can be dispatched
+ *     before the task must yield to other tasks waiting to execute.  If
+ *     quantum is zero, then the default quantum of the task manager will
+ *     be used.
+ *
+ *\li  The 'quantum' option may be removed from isc_task_create() in the
+ *     future.  If this happens, isc_task_getquantum() and
+ *     isc_task_setquantum() will be provided.
+ *
+ * Requires:
+ *
+ *\li  'manager' is a valid task manager.
+ *
+ *\li  taskp != NULL && *taskp == NULL
+ *
+ * Ensures:
+ *
+ *\li  On success, '*taskp' is bound to the new task.
+ *
+ * Returns:
+ *
+ *\li   #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_UNEXPECTED
+ *\li  #ISC_R_SHUTTINGDOWN
+ */
+
+void
+isc_task_attach(isc_task_t *source, isc_task_t **targetp);
+/*%<
+ * Attach *targetp to source.
+ *
+ * Requires:
+ *
+ *\li  'source' is a valid task.
+ *
+ *\li  'targetp' points to a NULL isc_task_t *.
+ *
+ * Ensures:
+ *
+ *\li  *targetp is attached to source.
+ */
+
+void
+isc_task_detach(isc_task_t **taskp);
+/*%<
+ * Detach *taskp from its task.
+ *
+ * Requires:
+ *
+ *\li  '*taskp' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li  *taskp is NULL.
+ *
+ *\li  If '*taskp' is the last reference to the task, the task is idle (has
+ *     an empty event queue), and has not been shutdown, the task will be
+ *     shutdown.
+ *
+ *\li  If '*taskp' is the last reference to the task and
+ *     the task has been shutdown,
+ *             all resources used by the task will be freed.
+ */
+
+void
+isc_task_send(isc_task_t *task, isc_event_t **eventp);
+/*%<
+ * Send '*event' to 'task'.
+ *
+ * Requires:
+ *
+ *\li  'task' is a valid task.
+ *\li  eventp != NULL && *eventp != NULL.
+ *
+ * Ensures:
+ *
+ *\li  *eventp == NULL.
+ */
+
+void
+isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp);
+/*%<
+ * Send '*event' to '*taskp' and then detach '*taskp' from its
+ * task.
+ *
+ * Requires:
+ *
+ *\li  '*taskp' is a valid task.
+ *\li  eventp != NULL && *eventp != NULL.
+ *
+ * Ensures:
+ *
+ *\li  *eventp == NULL.
+ *
+ *\li  *taskp == NULL.
+ *
+ *\li  If '*taskp' is the last reference to the task, the task is
+ *     idle (has an empty event queue), and has not been shutdown,
+ *     the task will be shutdown.
+ *
+ *\li  If '*taskp' is the last reference to the task and
+ *     the task has been shutdown,
+ *             all resources used by the task will be freed.
+ */
+
+
+unsigned int
+isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
+                   isc_eventtype_t last, void *tag);
+/*%<
+ * Purge events from a task's event queue.
+ *
+ * Requires:
+ *
+ *\li  'task' is a valid task.
+ *
+ *\li  last >= first
+ *
+ * Ensures:
+ *
+ *\li  Events in the event queue of 'task' whose sender is 'sender', whose
+ *     type is >= first and <= last, and whose tag is 'tag' will be purged,
+ *     unless they are marked as unpurgable.
+ *
+ *\li  A sender of NULL will match any sender.  A NULL tag matches any
+ *     tag.
+ *
+ * Returns:
+ *
+ *\li  The number of events purged.
+ */
+
+unsigned int
+isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
+              void *tag);
+/*%<
+ * Purge events from a task's event queue.
+ *
+ * Notes:
+ *
+ *\li  This function is equivalent to
+ *
+ *\code
+ *             isc_task_purgerange(task, sender, type, type, tag);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li  'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li  Events in the event queue of 'task' whose sender is 'sender', whose
+ *     type is 'type', and whose tag is 'tag' will be purged, unless they
+ *     are marked as unpurgable.
+ *
+ *\li  A sender of NULL will match any sender.  A NULL tag matches any
+ *     tag.
+ *
+ * Returns:
+ *
+ *\li  The number of events purged.
+ */
+
+isc_boolean_t
+isc_task_purgeevent(isc_task_t *task, isc_event_t *event);
+/*%<
+ * Purge 'event' from a task's event queue.
+ *
+ * XXXRTH:  WARNING:  This method may be removed before beta.
+ *
+ * Notes:
+ *
+ *\li  If 'event' is on the task's event queue, it will be purged,
+ *     unless it is marked as unpurgeable.  'event' does not have to be
+ *     on the task's event queue; in fact, it can even be an invalid
+ *     pointer.  Purging only occurs if the event is actually on the task's
+ *     event queue.
+ *
+ * \li Purging never changes the state of the task.
+ *
+ * Requires:
+ *
+ *\li  'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li  'event' is not in the event queue for 'task'.
+ *
+ * Returns:
+ *
+ *\li  #ISC_TRUE                       The event was purged.
+ *\li  #ISC_FALSE                      The event was not in the event queue,
+ *                                     or was marked unpurgeable.
+ */
+
+unsigned int
+isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
+                    isc_eventtype_t last, void *tag, isc_eventlist_t *events);
+/*%<
+ * Remove events from a task's event queue.
+ *
+ * Requires:
+ *
+ *\li  'task' is a valid task.
+ *
+ *\li  last >= first.
+ *
+ *\li  *events is a valid list.
+ *
+ * Ensures:
+ *
+ *\li  Events in the event queue of 'task' whose sender is 'sender', whose
+ *     type is >= first and <= last, and whose tag is 'tag' will be dequeued
+ *     and appended to *events.
+ *
+ *\li  A sender of NULL will match any sender.  A NULL tag matches any
+ *     tag.
+ *
+ * Returns:
+ *
+ *\li  The number of events unsent.
+ */
+
+unsigned int
+isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
+               void *tag, isc_eventlist_t *events);
+/*%<
+ * Remove events from a task's event queue.
+ *
+ * Notes:
+ *
+ *\li  This function is equivalent to
+ *
+ *\code
+ *             isc_task_unsendrange(task, sender, type, type, tag, events);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li  'task' is a valid task.
+ *
+ *\li  *events is a valid list.
+ *
+ * Ensures:
+ *
+ *\li  Events in the event queue of 'task' whose sender is 'sender', whose
+ *     type is 'type', and whose tag is 'tag' will be dequeued and appended
+ *     to *events.
+ *
+ * Returns:
+ *
+ *\li  The number of events unsent.
+ */
+
+isc_result_t
+isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action,
+                   const void *arg);
+/*%<
+ * Send a shutdown event with action 'action' and argument 'arg' when
+ * 'task' is shutdown.
+ *
+ * Notes:
+ *
+ *\li  Shutdown events are posted in LIFO order.
+ *
+ * Requires:
+ *
+ *\li  'task' is a valid task.
+ *
+ *\li  'action' is a valid task action.
+ *
+ * Ensures:
+ *
+ *\li  When the task is shutdown, shutdown events requested with
+ *     isc_task_onshutdown() will be appended to the task's event queue.
+ *
+
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_TASKSHUTTINGDOWN                 Task is shutting down.
+ */
+
+void
+isc_task_shutdown(isc_task_t *task);
+/*%<
+ * Shutdown 'task'.
+ *
+ * Notes:
+ *
+ *\li  Shutting down a task causes any shutdown events requested with
+ *     isc_task_onshutdown() to be posted (in LIFO order).  The task
+ *     moves into a "shutting down" mode which prevents further calls
+ *     to isc_task_onshutdown().
+ *
+ *\li  Trying to shutdown a task that has already been shutdown has no
+ *     effect.
+ *
+ * Requires:
+ *
+ *\li  'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li  Any shutdown events requested with isc_task_onshutdown() have been
+ *     posted (in LIFO order).
+ */
+
+void
+isc_task_destroy(isc_task_t **taskp);
+/*%<
+ * Destroy '*taskp'.
+ *
+ * Notes:
+ *
+ *\li  This call is equivalent to:
+ *
+ *\code
+ *             isc_task_shutdown(*taskp);
+ *             isc_task_detach(taskp);
+ *\endcode
+ *
+ * Requires:
+ *
+ *     '*taskp' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li  Any shutdown events requested with isc_task_onshutdown() have been
+ *     posted (in LIFO order).
+ *
+ *\li  *taskp == NULL
+ *
+ *\li  If '*taskp' is the last reference to the task,
+ *             all resources used by the task will be freed.
+ */
+
+void
+isc_task_setname(isc_task_t *task, const char *name, void *tag);
+/*%<
+ * Name 'task'.
+ *
+ * Notes:
+ *
+ *\li  Only the first 15 characters of 'name' will be copied.
+ *
+ *\li  Naming a task is currently only useful for debugging purposes.
+ *
+ * Requires:
+ *
+ *\li  'task' is a valid task.
+ */
+
+const char *
+isc_task_getname(isc_task_t *task);
+/*%<
+ * Get the name of 'task', as previously set using isc_task_setname().
+ *
+ * Notes:
+ *\li  This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li  'task' is a valid task.
+ *
+ * Returns:
+ *\li  A non-NULL pointer to a null-terminated string.
+ *     If the task has not been named, the string is
+ *     empty.
+ *
+ */
+
+void *
+isc_task_gettag(isc_task_t *task);
+/*%<
+ * Get the tag value for  'task', as previously set using isc_task_settag().
+ *
+ * Notes:
+ *\li  This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li  'task' is a valid task.
+ */
+
+isc_result_t
+isc_task_beginexclusive(isc_task_t *task);
+/*%<
+ * Request exclusive access for 'task', which must be the calling
+ * task.  Waits for any other concurrently executing tasks to finish their
+ * current event, and prevents any new events from executing in any of the
+ * tasks sharing a task manager with 'task'.
+ *
+ * The exclusive access must be relinquished by calling
+ * isc_task_endexclusive() before returning from the current event handler.
+ *
+ * Requires:
+ *\li  'task' is the calling task.
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS          The current task now has exclusive access.
+ *\li  #ISC_R_LOCKBUSY         Another task has already requested exclusive
+ *                             access.
+ */
+
+void
+isc_task_endexclusive(isc_task_t *task);
+/*%<
+ * Relinquish the exclusive access obtained by isc_task_beginexclusive(),
+ * allowing other tasks to execute.
+ *
+ * Requires:
+ *\li  'task' is the calling task, and has obtained
+ *             exclusive access by calling isc_task_spl().
+ */
+
+void
+isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t);
+/*%<
+ * Provide the most recent timestamp on the task.  The timestamp is considered
+ * as the "current time" in the second-order granularity.
+ *
+ * Requires:
+ *\li  'task' is a valid task.
+ *\li  't' is a valid non NULL pointer.
+ *
+ * Ensures:
+ *\li  '*t' has the "current time".
+ */
+
+/*****
+ ***** Task Manager.
+ *****/
+
+isc_result_t
+isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
+                  unsigned int default_quantum, isc_taskmgr_t **managerp);
+/*%<
+ * Create a new task manager.
+ *
+ * Notes:
+ *
+ *\li  'workers' in the number of worker threads to create.  In general,
+ *     the value should be close to the number of processors in the system.
+ *     The 'workers' value is advisory only.  An attempt will be made to
+ *     create 'workers' threads, but if at least one thread creation
+ *     succeeds, isc_taskmgr_create() may return ISC_R_SUCCESS.
+ *
+ *\li  If 'default_quantum' is non-zero, then it will be used as the default
+ *     quantum value when tasks are created.  If zero, then an implementation
+ *     defined default quantum will be used.
+ *
+ * Requires:
+ *
+ *\li      'mctx' is a valid memory context.
+ *
+ *\li  workers > 0
+ *
+ *\li  managerp != NULL && *managerp == NULL
+ *
+ * Ensures:
+ *
+ *\li  On success, '*managerp' will be attached to the newly created task
+ *     manager.
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_NOTHREADS                        No threads could be created.
+ *\li  #ISC_R_UNEXPECTED               An unexpected error occurred.
+ */
+
+void
+isc_taskmgr_destroy(isc_taskmgr_t **managerp);
+/*%<
+ * Destroy '*managerp'.
+ *
+ * Notes:
+ *
+ *\li  Calling isc_taskmgr_destroy() will shutdown all tasks managed by
+ *     *managerp that haven't already been shutdown.  The call will block
+ *     until all tasks have entered the done state.
+ *
+ *\li  isc_taskmgr_destroy() must not be called by a task event action,
+ *     because it would block forever waiting for the event action to
+ *     complete.  An event action that wants to cause task manager shutdown
+ *     should request some non-event action thread of execution to do the
+ *     shutdown, e.g. by signaling a condition variable or using
+ *     isc_app_shutdown().
+ *
+ *\li  Task manager references are not reference counted, so the caller
+ *     must ensure that no attempt will be made to use the manager after
+ *     isc_taskmgr_destroy() returns.
+ *
+ * Requires:
+ *
+ *\li  '*managerp' is a valid task manager.
+ *
+ *\li  isc_taskmgr_destroy() has not be called previously on '*managerp'.
+ *
+ * Ensures:
+ *
+ *\li  All resources used by the task manager, and any tasks it managed,
+ *     have been freed.
+ */
+
+#ifdef HAVE_LIBXML2
+
+void
+isc_taskmgr_renderxml(isc_taskmgr_t *mgr, xmlTextWriterPtr writer);
+
+#endif
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TASK_H */
diff --git a/lib/isc/include/isc/taskpool.h b/lib/isc/include/isc/taskpool.h
new file mode 100644 (file)
index 0000000..fd07bfd
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: taskpool.h,v 1.15 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_TASKPOOL_H
+#define ISC_TASKPOOL_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/taskpool.h
+ * \brief A task pool is a mechanism for sharing a small number of tasks
+ * among a large number of objects such that each object is
+ * assigned a unique task, but each task may be shared by several
+ * objects.
+ *
+ * Task pools are used to let objects that can exist in large
+ * numbers (e.g., zones) use tasks for synchronization without
+ * the memory overhead and unfair scheduling competition that
+ * could result from creating a separate task for each object.
+ */
+
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/task.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Types.
+ *****/
+
+typedef struct isc_taskpool isc_taskpool_t;
+
+/*****
+ ***** Functions.
+ *****/
+
+isc_result_t
+isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx,
+                   unsigned int ntasks, unsigned int quantum,
+                   isc_taskpool_t **poolp);
+/*%<
+ * Create a task pool of "ntasks" tasks, each with quantum
+ * "quantum".
+ *
+ * Requires:
+ *
+ *\li  'tmgr' is a valid task manager.
+ *
+ *\li  'mctx' is a valid memory context.
+ *
+ *\li  poolp != NULL && *poolp == NULL
+ *
+ * Ensures:
+ *
+ *\li  On success, '*taskp' points to the new task pool.
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_UNEXPECTED
+ */
+
+void 
+isc_taskpool_gettask(isc_taskpool_t *pool, unsigned int hash,
+                         isc_task_t **targetp);
+/*%<
+ * Attach to the task corresponding to the hash value "hash".
+ */
+
+void
+isc_taskpool_destroy(isc_taskpool_t **poolp);
+/*%<
+ * Destroy a task pool.  The tasks in the pool are detached but not
+ * shut down.
+ *
+ * Requires:
+ * \li '*poolp' is a valid task pool.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TASKPOOL_H */
diff --git a/lib/isc/include/isc/timer.h b/lib/isc/include/isc/timer.h
new file mode 100644 (file)
index 0000000..a4b2df7
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: timer.h,v 1.40 2008/06/23 23:47:11 tbox Exp $ */
+
+#ifndef ISC_TIMER_H
+#define ISC_TIMER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/timer.h
+ * \brief Provides timers which are event sources in the task system.
+ *
+ * Three types of timers are supported:
+ *
+ *\li  'ticker' timers generate a periodic tick event.
+ *
+ *\li  'once' timers generate an idle timeout event if they are idle for too
+ *     long, and generate a life timeout event if their lifetime expires.
+ *     They are used to implement both (possibly expiring) idle timers and
+ *     'one-shot' timers.
+ *
+ *\li  'limited' timers generate a periodic tick event until they reach
+ *     their lifetime when they generate a life timeout event.
+ *
+ *\li  'inactive' timers generate no events.
+ *
+ * Timers can change type.  It is typical to create a timer as
+ * an 'inactive' timer and then change it into a 'ticker' or
+ * 'once' timer.
+ *
+ *\li MP:
+ *     The module ensures appropriate synchronization of data structures it
+ *     creates and manipulates.
+ *     Clients of this module must not be holding a timer's task's lock when
+ *     making a call that affects that timer.  Failure to follow this rule
+ *     can result in deadlock.
+ *     The caller must ensure that isc_timermgr_destroy() is called only
+ *     once for a given manager.
+ *
+ * \li Reliability:
+ *     No anticipated impact.
+ *
+ * \li Resources:
+ *     TBS
+ *
+ * \li Security:
+ *     No anticipated impact.
+ *
+ * \li Standards:
+ *     None.
+ */
+
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/types.h>
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/time.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+/*% Timer Type */
+typedef enum {
+       isc_timertype_ticker = 0,       /*%< Ticker */
+       isc_timertype_once = 1,         /*%< Once */
+       isc_timertype_limited = 2,      /*%< Limited */
+       isc_timertype_inactive = 3      /*%< Inactive */
+} isc_timertype_t;
+
+typedef struct isc_timerevent {
+       struct isc_event        common;
+       isc_time_t              due;
+} isc_timerevent_t;
+
+#define ISC_TIMEREVENT_FIRSTEVENT      (ISC_EVENTCLASS_TIMER + 0)
+#define ISC_TIMEREVENT_TICK            (ISC_EVENTCLASS_TIMER + 1)
+#define ISC_TIMEREVENT_IDLE            (ISC_EVENTCLASS_TIMER + 2)
+#define ISC_TIMEREVENT_LIFE            (ISC_EVENTCLASS_TIMER + 3)
+#define ISC_TIMEREVENT_LASTEVENT       (ISC_EVENTCLASS_TIMER + 65535)
+
+/***
+ *** Timer and Timer Manager Functions
+ ***
+ *** Note: all Ensures conditions apply only if the result is success for
+ *** those functions which return an isc_result_t.
+ ***/
+
+isc_result_t
+isc_timer_create(isc_timermgr_t *manager,
+                isc_timertype_t type,
+                isc_time_t *expires,
+                isc_interval_t *interval,
+                isc_task_t *task,
+                isc_taskaction_t action,
+                const void *arg,
+                isc_timer_t **timerp);
+/*%<
+ * Create a new 'type' timer managed by 'manager'.  The timers parameters
+ * are specified by 'expires' and 'interval'.  Events will be posted to
+ * 'task' and when dispatched 'action' will be called with 'arg' as the
+ * arg value.  The new timer is returned in 'timerp'.
+ *
+ * Notes:
+ *
+ *\li  For ticker timers, the timer will generate a 'tick' event every
+ *     'interval' seconds.  The value of 'expires' is ignored.
+ *
+ *\li  For once timers, 'expires' specifies the time when a life timeout
+ *     event should be generated.  If 'expires' is 0 (the epoch), then no life
+ *     timeout will be generated.  'interval' specifies how long the timer
+ *     can be idle before it generates an idle timeout.  If 0, then no
+ *     idle timeout will be generated.
+ *
+ *\li  If 'expires' is NULL, the epoch will be used.
+ *
+ *     If 'interval' is NULL, the zero interval will be used.
+ *
+ * Requires:
+ *
+ *\li  'manager' is a valid manager
+ *
+ *\li  'task' is a valid task
+ *
+ *\li  'action' is a valid action
+ *
+ *\li  'expires' points to a valid time, or is NULL.
+ *
+ *\li  'interval' points to a valid interval, or is NULL.
+ *
+ *\li  type == isc_timertype_inactive ||
+ *     ('expires' and 'interval' are not both 0)
+ *
+ *\li  'timerp' is a valid pointer, and *timerp == NULL
+ *
+ * Ensures:
+ *
+ *\li  '*timerp' is attached to the newly created timer
+ *
+ *\li  The timer is attached to the task
+ *
+ *\li  An idle timeout will not be generated until at least Now + the
+ *     timer's interval if 'timer' is a once timer with a non-zero
+ *     interval.
+ *
+ * Returns:
+ *
+ *\li  Success
+ *\li  No memory
+ *\li  Unexpected error
+ */
+
+isc_result_t
+isc_timer_reset(isc_timer_t *timer,
+               isc_timertype_t type,
+               isc_time_t *expires,
+               isc_interval_t *interval,
+               isc_boolean_t purge);
+/*%<
+ * Change the timer's type, expires, and interval values to the given
+ * values.  If 'purge' is TRUE, any pending events from this timer
+ * are purged from its task's event queue.
+ *
+ * Notes:
+ *
+ *\li  If 'expires' is NULL, the epoch will be used.
+ *
+ *\li  If 'interval' is NULL, the zero interval will be used.
+ *
+ * Requires:
+ *
+ *\li  'timer' is a valid timer
+ *
+ *\li  The same requirements that isc_timer_create() imposes on 'type',
+ *     'expires' and 'interval' apply.
+ *
+ * Ensures:
+ *
+ *\li  An idle timeout will not be generated until at least Now + the
+ *     timer's interval if 'timer' is a once timer with a non-zero
+ *     interval.
+ *
+ * Returns:
+ *
+ *\li  Success
+ *\li  No memory
+ *\li  Unexpected error
+ */
+
+isc_result_t
+isc_timer_touch(isc_timer_t *timer);
+/*%<
+ * Set the last-touched time of 'timer' to the current time.
+ *
+ * Requires:
+ *
+ *\li  'timer' is a valid once timer.
+ *
+ * Ensures:
+ *
+ *\li  An idle timeout will not be generated until at least Now + the
+ *     timer's interval if 'timer' is a once timer with a non-zero
+ *     interval.
+ *
+ * Returns:
+ *
+ *\li  Success
+ *\li  Unexpected error
+ */
+
+void
+isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp);
+/*%<
+ * Attach *timerp to timer.
+ *
+ * Requires:
+ *
+ *\li  'timer' is a valid timer.
+ *
+ *\li  'timerp' points to a NULL timer.
+ *
+ * Ensures:
+ *
+ *\li  *timerp is attached to timer.
+ */
+
+void
+isc_timer_detach(isc_timer_t **timerp);
+/*%<
+ * Detach *timerp from its timer.
+ *
+ * Requires:
+ *
+ *\li  'timerp' points to a valid timer.
+ *
+ * Ensures:
+ *
+ *\li  *timerp is NULL.
+ *
+ *\li  If '*timerp' is the last reference to the timer,
+ *     then:
+ *
+ *\code
+ *             The timer will be shutdown
+ *
+ *             The timer will detach from its task
+ *
+ *             All resources used by the timer have been freed
+ *
+ *             Any events already posted by the timer will be purged.
+ *             Therefore, if isc_timer_detach() is called in the context
+ *             of the timer's task, it is guaranteed that no more
+ *             timer event callbacks will run after the call.
+ *\endcode
+ */
+
+isc_timertype_t
+isc_timer_gettype(isc_timer_t *timer);
+/*%<
+ * Return the timer type.
+ *
+ * Requires:
+ *
+ *\li  'timer' to be a valid timer.
+ */
+
+isc_result_t
+isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp);
+/*%<
+ * Create a timer manager.
+ *
+ * Notes:
+ *
+ *\li  All memory will be allocated in memory context 'mctx'.
+ *
+ * Requires:
+ *
+ *\li  'mctx' is a valid memory context.
+ *
+ *\li  'managerp' points to a NULL isc_timermgr_t.
+ *
+ * Ensures:
+ *
+ *\li  '*managerp' is a valid isc_timermgr_t.
+ *
+ * Returns:
+ *
+ *\li  Success
+ *\li  No memory
+ *\li  Unexpected error
+ */
+
+void
+isc_timermgr_destroy(isc_timermgr_t **managerp);
+/*%<
+ * Destroy a timer manager.
+ *
+ * Notes:
+ *
+ *\li  This routine blocks until there are no timers left in the manager,
+ *     so if the caller holds any timer references using the manager, it
+ *     must detach them before calling isc_timermgr_destroy() or it will
+ *     block forever.
+ *
+ * Requires:
+ *
+ *\li  '*managerp' is a valid isc_timermgr_t.
+ *
+ * Ensures:
+ *
+ *\li  *managerp == NULL
+ *
+ *\li  All resources used by the manager have been freed.
+ */
+
+void isc_timermgr_poke(isc_timermgr_t *m);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TIMER_H */
index b30f55ee7fe9151d5263d7f85ddb12a85aff5784..4dccbf981569777f143c7dfdcfdbb46346a5e5aa 100644 (file)
@@ -1,26 +1,27 @@
 /*
- * Copyright (C) 1999-2001  Internet Software Consortium.
+ * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: types.h,v 1.33 2002/07/19 03:39:44 marka Exp $ */
+/* $Id: types.h,v 1.46.84.2 2009/01/29 23:47:44 tbox Exp $ */
 
 #ifndef ISC_TYPES_H
 #define ISC_TYPES_H 1
 
-/*
+/*! \file isc/types.h
+ * \brief
  * OS-specific types, from the OS-specific include directories.
  */
 #include <isc/int.h>
  */
 #include <isc/list.h>
 
-/***
- *** Core Types.  Alphabetized by defined type.
- ***/
+/* Core Types.  Alphabetized by defined type. */
 
-typedef struct isc_bitstring           isc_bitstring_t;
-typedef struct isc_buffer              isc_buffer_t;
-typedef ISC_LIST(isc_buffer_t)         isc_bufferlist_t;
-typedef struct isc_constregion         isc_constregion_t;
-typedef struct isc_consttextregion     isc_consttextregion_t;
-typedef struct isc_entropy             isc_entropy_t;
-typedef struct isc_entropysource       isc_entropysource_t;
-typedef struct isc_event               isc_event_t;
-typedef ISC_LIST(isc_event_t)          isc_eventlist_t;
-typedef unsigned int                   isc_eventtype_t;
-typedef isc_uint32_t                   isc_fsaccess_t;
-typedef struct isc_interface           isc_interface_t;
-typedef struct isc_interfaceiter       isc_interfaceiter_t;
-typedef struct isc_interval            isc_interval_t;
-typedef struct isc_lex                 isc_lex_t;
-typedef struct isc_log                         isc_log_t;
-typedef struct isc_logcategory         isc_logcategory_t;
-typedef struct isc_logconfig           isc_logconfig_t;
-typedef struct isc_logmodule           isc_logmodule_t;
-typedef struct isc_mem                 isc_mem_t;
-typedef struct isc_mempool             isc_mempool_t;
-typedef struct isc_msgcat              isc_msgcat_t;
-typedef struct isc_ondestroy           isc_ondestroy_t;
-typedef struct isc_netaddr             isc_netaddr_t;
-typedef struct isc_quota               isc_quota_t;
-typedef struct isc_random              isc_random_t;
-typedef struct isc_ratelimiter         isc_ratelimiter_t;
-typedef struct isc_region              isc_region_t;
-typedef isc_uint64_t                   isc_resourcevalue_t;
-typedef unsigned int                   isc_result_t;
-typedef struct isc_rwlock              isc_rwlock_t;
-typedef struct isc_sockaddr            isc_sockaddr_t;
-typedef struct isc_socket              isc_socket_t;
-typedef struct isc_socketevent         isc_socketevent_t;
-typedef struct isc_socketmgr           isc_socketmgr_t;
-typedef struct isc_symtab              isc_symtab_t;
-typedef struct isc_task                        isc_task_t;
-typedef ISC_LIST(isc_task_t)           isc_tasklist_t;
-typedef struct isc_taskmgr             isc_taskmgr_t;
-typedef struct isc_textregion          isc_textregion_t;
-typedef struct isc_time                        isc_time_t;
-typedef struct isc_timer               isc_timer_t;
-typedef struct isc_timermgr            isc_timermgr_t;
+typedef struct isc_bitstring           isc_bitstring_t;        /*%< Bitstring */
+typedef struct isc_buffer              isc_buffer_t;           /*%< Buffer */
+typedef ISC_LIST(isc_buffer_t)         isc_bufferlist_t;       /*%< Buffer List */
+typedef struct isc_constregion         isc_constregion_t;      /*%< Const region */
+typedef struct isc_consttextregion     isc_consttextregion_t;  /*%< Const Text Region */
+typedef struct isc_entropy             isc_entropy_t;          /*%< Entropy */
+typedef struct isc_entropysource       isc_entropysource_t;    /*%< Entropy Source */
+typedef struct isc_event               isc_event_t;            /*%< Event */
+typedef ISC_LIST(isc_event_t)          isc_eventlist_t;        /*%< Event List */
+typedef unsigned int                   isc_eventtype_t;        /*%< Event Type */
+typedef isc_uint32_t                   isc_fsaccess_t;         /*%< FS Access */
+typedef struct isc_hash                        isc_hash_t;             /*%< Hash */
+typedef struct isc_httpd               isc_httpd_t;            /*%< HTTP client */
+typedef void (isc_httpdfree_t)(isc_buffer_t *, void *);                /*%< HTTP free function */
+typedef struct isc_httpdmgr            isc_httpdmgr_t;         /*%< HTTP manager */
+typedef struct isc_httpdurl            isc_httpdurl_t;         /*%< HTTP URL */
+typedef void (isc_httpdondestroy_t)(void *);                   /*%< Callback on destroying httpd */
+typedef struct isc_interface           isc_interface_t;        /*%< Interface */
+typedef struct isc_interfaceiter       isc_interfaceiter_t;    /*%< Interface Iterator */
+typedef struct isc_interval            isc_interval_t;         /*%< Interval */
+typedef struct isc_lex                 isc_lex_t;              /*%< Lex */
+typedef struct isc_log                         isc_log_t;              /*%< Log */
+typedef struct isc_logcategory         isc_logcategory_t;      /*%< Log Category */
+typedef struct isc_logconfig           isc_logconfig_t;        /*%< Log Configuration */
+typedef struct isc_logmodule           isc_logmodule_t;        /*%< Log Module */
+typedef struct isc_mem                 isc_mem_t;              /*%< Memory */
+typedef struct isc_mempool             isc_mempool_t;          /*%< Memory Pool */
+typedef struct isc_msgcat              isc_msgcat_t;           /*%< Message Catalog */
+typedef struct isc_ondestroy           isc_ondestroy_t;        /*%< On Destroy */
+typedef struct isc_netaddr             isc_netaddr_t;          /*%< Net Address */
+typedef struct isc_portset             isc_portset_t;          /*%< Port Set */
+typedef struct isc_quota               isc_quota_t;            /*%< Quota */
+typedef struct isc_random              isc_random_t;           /*%< Random */
+typedef struct isc_ratelimiter         isc_ratelimiter_t;      /*%< Rate Limiter */
+typedef struct isc_region              isc_region_t;           /*%< Region */
+typedef isc_uint64_t                   isc_resourcevalue_t;    /*%< Resource Value */
+typedef unsigned int                   isc_result_t;           /*%< Result */
+typedef struct isc_rwlock              isc_rwlock_t;           /*%< Read Write Lock */
+typedef struct isc_sockaddr            isc_sockaddr_t;         /*%< Socket Address */
+typedef struct isc_socket              isc_socket_t;           /*%< Socket */
+typedef struct isc_socketevent         isc_socketevent_t;      /*%< Socket Event */
+typedef struct isc_socketmgr           isc_socketmgr_t;        /*%< Socket Manager */
+typedef struct isc_stats               isc_stats_t;            /*%< Statistics */
+typedef int                            isc_statscounter_t;     /*%< Statistics Counter */
+typedef struct isc_symtab              isc_symtab_t;           /*%< Symbol Table */
+typedef struct isc_task                        isc_task_t;             /*%< Task */
+typedef ISC_LIST(isc_task_t)           isc_tasklist_t;         /*%< Task List */
+typedef struct isc_taskmgr             isc_taskmgr_t;          /*%< Task Manager */
+typedef struct isc_textregion          isc_textregion_t;       /*%< Text Region */
+typedef struct isc_time                        isc_time_t;             /*%< Time */
+typedef struct isc_timer               isc_timer_t;            /*%< Timer */
+typedef struct isc_timermgr            isc_timermgr_t;         /*%< Timer Manager */
 
 typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *);
+typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *);
+
+/* The following cannot be listed alphabetically due to forward reference */
+typedef isc_result_t (isc_httpdaction_t)(const char *url,
+                                        const char *querystring,
+                                        void *arg,
+                                        unsigned int *retcode,
+                                        const char **retmsg,
+                                        const char **mimetype,
+                                        isc_buffer_t *body,
+                                        isc_httpdfree_t **freecb,
+                                        void **freecb_args);
+typedef isc_boolean_t (isc_httpdclientok_t)(const isc_sockaddr_t *, void *);
 
+/*% Resource */
 typedef enum {
        isc_resource_coresize = 1,
        isc_resource_cputime,
index 6144e11ba863ca0da7572b7a35a7d31fd49c66cb..8a3b95d9da36f1b21b7306f6e3faad44f7c57446 100644 (file)
@@ -1,31 +1,32 @@
 /*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: util.h,v 1.23 2001/11/30 01:59:38 gson Exp $ */
+/* $Id: util.h,v 1.30 2007/06/19 23:47:18 tbox Exp $ */
 
 #ifndef ISC_UTIL_H
 #define ISC_UTIL_H 1
 
-/*
+/*! \file isc/util.h
  * NOTE:
  *
  * This file is not to be included from any <isc/???.h> (or other) library
  * files.
  *
+ * \brief
  * Including this file puts several macros in your name space that are
  * not protected (as all the other ISC functions/macros do) by prepending
  * ISC_ or isc_ to the name.
  *** General Macros.
  ***/
 
-/*
+/*%
  * Use this to hide unused function arguments.
- *
+ * \code
  * int
  * foo(char *bar)
  * {
  *     UNUSED(bar);
  * }
+ * \endcode
  */
 #define UNUSED(x)      (void)(x)
 
 #define ISC_MAX(a, b)  ((a) > (b) ? (a) : (b))
 #define ISC_MIN(a, b)  ((a) < (b) ? (a) : (b))
 
-/*
+/*%
  * Use this to remove the const qualifier of a variable to assign it to
  * a non-const variable or pass it as a non-const function argument ...
  * but only when you are sure it won't then be changed!
                var = _u.v; \
        } while (0)
 
-/*
+/*%
  * Use this in translation units that would otherwise be empty, to
  * suppress compiler warnings.
  */
 #define EMPTY_TRANSLATION_UNIT static void isc__empty(void) { isc__empty(); }
 
-/*
+/*%
  * We use macros instead of calling the routines directly because
  * the capital letters make the locking stand out.
- *
  * We RUNTIME_CHECK for success since in general there's no way
  * for us to continue if they fail.
  */
  */
 #include <isc/assertions.h>    /* Contractual promise. */
 
+/*% Require Assertion */
 #define REQUIRE(e)                     ISC_REQUIRE(e)
+/*% Ensure Assertion */
 #define ENSURE(e)                      ISC_ENSURE(e)
+/*% Insist Assertion */
 #define INSIST(e)                      ISC_INSIST(e)
+/*% Invariant Assertion */
 #define INVARIANT(e)                   ISC_INVARIANT(e)
 
 /*
  */
 #include <isc/error.h>         /* Contractual promise. */
 
+/*% Unexpected Error */
 #define UNEXPECTED_ERROR               isc_error_unexpected
+/*% Fatal Error */
 #define FATAL_ERROR                    isc_error_fatal
+/*% Runtime Check */
 #define RUNTIME_CHECK(cond)            ISC_ERROR_RUNTIMECHECK(cond)
 
-/*
+/*%
  * Time
  */
 #define TIME_NOW(tp)   RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
diff --git a/lib/isc/include/isc/version.h b/lib/isc/include/isc/version.h
new file mode 100644 (file)
index 0000000..ec00bde
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: version.h,v 1.9 2007/06/19 23:47:18 tbox Exp $ */
+
+/*! \file isc/version.h */
+
+#include <isc/platform.h>
+
+LIBISC_EXTERNAL_DATA extern const char isc_version[];
+
+LIBISC_EXTERNAL_DATA extern const unsigned int isc_libinterface;
+LIBISC_EXTERNAL_DATA extern const unsigned int isc_librevision;
+LIBISC_EXTERNAL_DATA extern const unsigned int isc_libage;
diff --git a/lib/isc/include/isc/xml.h b/lib/isc/include/isc/xml.h
new file mode 100644 (file)
index 0000000..d31a31a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006, 2007  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: xml.h,v 1.4 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_XML_H
+#define ISC_XML_H 1
+
+/*
+ * This file is here mostly to make it easy to add additional libxml header
+ * files as needed across all the users of this file.  Rather than place
+ * these libxml includes in each file, one include makes it easy to handle
+ * the ifdef as well as adding the ability to add additional functions
+ * which may be useful.
+ */
+
+#ifdef HAVE_LIBXML2
+#include <libxml/encoding.h>
+#include <libxml/xmlwriter.h>
+#endif
+
+#define ISC_XMLCHAR (const xmlChar *)
+
+#define ISC_XML_RENDERCONFIG           0x00000001 /* render config data */
+#define ISC_XML_RENDERSTATS            0x00000002 /* render stats */
+#define ISC_XML_RENDERALL              0x000000ff /* render everything */
+
+#endif /* ISC_XML_H */
index 530b0103bab0918c91435bb00ccdf4ae0ac4974d..ad9401f696f0024280a64c610291e937b2a18bf3 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Portions Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
  * Portions Copyright (C) 1996-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  * SOFTWARE.
  */
+/*! \file */
 
 #if defined(LIBC_SCCS) && !defined(lint)
 static char sccsid[] = "@(#)inet_addr.c        8.1 (Berkeley) 6/17/93";
-static char rcsid[] = "$Id: inet_aton.c,v 1.15.12.3 2004/03/08 09:04:49 marka Exp $";
+static char rcsid[] = "$Id: inet_aton.c,v 1.21.332.2 2009/03/05 23:47:03 tbox Exp $";
 #endif /* LIBC_SCCS and not lint */
 
 #include <config.h>
@@ -81,7 +82,7 @@ static char rcsid[] = "$Id: inet_aton.c,v 1.15.12.3 2004/03/08 09:04:49 marka Ex
 #include <isc/types.h>
 #include <isc/net.h>
 
-/*
+/*%
  * Check whether "cp" is a valid ascii representation
  * of an Internet address and convert to a binary address.
  * Returns 1 if the address is valid, 0 if not.
@@ -144,7 +145,7 @@ isc_net_aton(const char *cp, struct in_addr *addr) {
                         *      a.b.c   (with c treated as 16 bits)
                         *      a.b     (with b treated as 24 bits)
                         */
-                       if (pp >= parts + 3 || val > 0xff)
+                       if (pp >= parts + 3 || val > 0xffU)
                                return (0);
                        *pp++ = (isc_uint8_t)val;
                        c = *++cp;
@@ -171,19 +172,19 @@ isc_net_aton(const char *cp, struct in_addr *addr) {
                break;
 
        case 2:                         /* a.b -- 8.24 bits */
-               if (val > 0xffffff)
+               if (val > 0xffffffU)
                        return (0);
                val |= parts[0] << 24;
                break;
 
        case 3:                         /* a.b.c -- 8.8.16 bits */
-               if (val > 0xffff)
+               if (val > 0xffffU)
                        return (0);
                val |= (parts[0] << 24) | (parts[1] << 16);
                break;
 
        case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
-               if (val > 0xff)
+               if (val > 0xffU)
                        return (0);
                val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
                break;
index feb85f1351eaa97b8eed16629a6e2915dc93d23f..dc053ededfba7d5abc655df77104355a0b255dac 100644 (file)
@@ -1,36 +1,35 @@
 /*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1996-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
+/*! \file */
+
 #if defined(LIBC_SCCS) && !defined(lint)
 static char rcsid[] =
-       "$Id: inet_ntop.c,v 1.13 2001/11/27 01:56:00 gson Exp $";
+       "$Id: inet_ntop.c,v 1.19 2007/06/19 23:47:17 tbox Exp $";
 #endif /* LIBC_SCCS and not lint */
 
 #include <config.h>
 
-#ifdef ISC_PLATFORM_NEEDNTOP
-
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 
 #include <isc/net.h>
-
-#include "ntp_sprintf.h"
+#include <isc/print.h>
 
 #define NS_INT16SZ      2
 #define NS_IN6ADDRSZ   16
@@ -48,12 +47,12 @@ static const char *inet_ntop6(const unsigned char *src, char *dst,
                              size_t size);
 #endif
 
-/* char *
+/*! char *
  * isc_net_ntop(af, src, dst, size)
  *     convert a network format address to presentation format.
- * return:
+ * \return
  *     pointer to presentation format address (`dst'), or NULL (see errno).
- * author:
+ * \author 
  *     Paul Vixie, 1996.
  */
 const char *
@@ -73,15 +72,16 @@ isc_net_ntop(int af, const void *src, char *dst, size_t size)
        /* NOTREACHED */
 }
 
-/* const char *
+/*! const char *
  * inet_ntop4(src, dst, size)
  *     format an IPv4 address
- * return:
+ * \return
  *     `dst' (as a const)
- * notes:
+ * \note
  *     (1) uses no statics
+ * \note
  *     (2) takes a unsigned char* not an in_addr as input
- * author:
+ * \author
  *     Paul Vixie, 1996.
  */
 static const char *
@@ -90,7 +90,7 @@ inet_ntop4(const unsigned char *src, char *dst, size_t size)
        static const char *fmt = "%u.%u.%u.%u";
        char tmp[sizeof("255.255.255.255")];
 
-       if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size)
+       if ((size_t)sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) >= size)
        {
                errno = ENOSPC;
                return (NULL);
@@ -100,10 +100,10 @@ inet_ntop4(const unsigned char *src, char *dst, size_t size)
        return (dst);
 }
 
-/* const char *
+/*! const char *
  * isc_inet_ntop6(src, dst, size)
  *     convert IPv6 binary address into presentation (printable) format
- * author:
+ * \author
  *     Paul Vixie, 1996.
  */
 #ifdef AF_INET6
@@ -131,9 +131,7 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size)
        for (i = 0; i < NS_IN6ADDRSZ; i++)
                words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
        best.base = -1;
-       best.len = 0;
        cur.base = -1;
-       cur.len = 0;
        for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
                if (words[i] == 0) {
                        if (cur.base == -1)
@@ -179,7 +177,7 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size)
                        tp += strlen(tp);
                        break;
                }
-               tp += SPRINTF((tp, "%x", words[i]));
+               tp += sprintf(tp, "%x", words[i]);
        }
        /* Was it a trailing run of 0x00's? */
        if (best.base != -1 && (best.base + best.len) ==
@@ -198,7 +196,3 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size)
        return (dst);
 }
 #endif /* AF_INET6 */
-
-#else
-int inet_ntop_c_not_empty;
-#endif /* ISC_PLATFORM_NEEDNTOP */
index 3416dffda6c4a8f50c74ffb1ad76eb99bebae676..6bada239e0e5e69a8930cbcb15808ca0cda08a3e 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1996-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
+/*! \file */
+
 #if defined(LIBC_SCCS) && !defined(lint)
 static char rcsid[] =
-       "$Id: inet_pton.c,v 1.10.2.4.2.1 2004/03/06 08:14:31 marka Exp $";
+       "$Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp $";
 #endif /* LIBC_SCCS and not lint */
 
 #include <config.h>
 
-#ifdef ISC_PLATFORM_NEEDPTON
-
 #include <errno.h>
 #include <string.h>
 
 #include <isc/net.h>
 
+/*% INT16 Size */
 #define NS_INT16SZ      2
+/*% IPv4 Address Size */
 #define NS_INADDRSZ     4
+/*% IPv6 Address Size */
 #define NS_IN6ADDRSZ   16
 
 /*
@@ -41,15 +44,14 @@ static char rcsid[] =
 static int inet_pton4(const char *src, unsigned char *dst);
 static int inet_pton6(const char *src, unsigned char *dst);
 
-/* int
- * isc_net_pton(af, src, dst)
+/*% 
  *     convert from presentation format (which usually means ASCII printable)
  *     to network format (which is usually some kind of binary format).
- * return:
+ * \return
  *     1 if the address was valid for the specified address family
  *     0 if the address wasn't valid (`dst' is untouched in this case)
  *     -1 if some other error occurred (`dst' is untouched in this case, too)
- * author:
+ * \author
  *     Paul Vixie, 1996.
  */
 int
@@ -66,14 +68,14 @@ isc_net_pton(int af, const char *src, void *dst) {
        /* NOTREACHED */
 }
 
-/* int
- * inet_pton4(src, dst)
+/*!\fn static int inet_pton4(const char *src, unsigned char *dst)
+ * \brief
  *     like inet_aton() but without all the hexadecimal and shorthand.
- * return:
+ * \return
  *     1 if `src' is a valid dotted quad, else 0.
- * notice:
+ * \note
  *     does not touch `dst' unless it's returning 1.
- * author:
+ * \author
  *     Paul Vixie, 1996.
  */
 static int
@@ -95,7 +97,7 @@ inet_pton4(const char *src, unsigned char *dst) {
                                return (0);
                        if (new > 255)
                                return (0);
-                       *tp = (unsigned char) new;
+                       *tp = new;
                        if (!saw_digit) {
                                if (++octets > 4)
                                        return (0);
@@ -115,17 +117,17 @@ inet_pton4(const char *src, unsigned char *dst) {
        return (1);
 }
 
-/* int
- * inet_pton6(src, dst)
+/*%
  *     convert presentation level address to network order binary form.
- * return:
+ * \return
  *     1 if `src' is a valid [RFC1884 2.2] address, else 0.
- * notice:
+ * \note
  *     (1) does not touch `dst' unless it's returning 1.
+ * \note
  *     (2) :: in a full address is silently ignored.
- * credit:
+ * \author
  *     inspired by Mark Andrews.
- * author:
+ * \author
  *     Paul Vixie, 1996.
  */
 static int
@@ -134,7 +136,7 @@ inet_pton6(const char *src, unsigned char *dst) {
                          xdigits_u[] = "0123456789ABCDEF";
        unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
        const char *xdigits, *curtok;
-       int ch, saw_xdigit;
+       int ch, seen_xdigits;
        unsigned int val;
 
        memset((tp = tmp), '\0', NS_IN6ADDRSZ);
@@ -145,7 +147,7 @@ inet_pton6(const char *src, unsigned char *dst) {
                if (*++src != ':')
                        return (0);
        curtok = src;
-       saw_xdigit = 0;
+       seen_xdigits = 0;
        val = 0;
        while ((ch = *src++) != '\0') {
                const char *pch;
@@ -155,14 +157,13 @@ inet_pton6(const char *src, unsigned char *dst) {
                if (pch != NULL) {
                        val <<= 4;
                        val |= (pch - xdigits);
-                       if (val > 0xffff)
+                       if (++seen_xdigits > 4)
                                return (0);
-                       saw_xdigit = 1;
                        continue;
                }
                if (ch == ':') {
                        curtok = src;
-                       if (!saw_xdigit) {
+                       if (!seen_xdigits) {
                                if (colonp)
                                        return (0);
                                colonp = tp;
@@ -170,25 +171,25 @@ inet_pton6(const char *src, unsigned char *dst) {
                        }
                        if (tp + NS_INT16SZ > endp)
                                return (0);
-                       *tp++ = (unsigned char) ((val >> 8) & 0xff);
-                       *tp++ = (unsigned char) (val & 0xff);
-                       saw_xdigit = 0;
+                       *tp++ = (unsigned char) (val >> 8) & 0xff;
+                       *tp++ = (unsigned char) val & 0xff;
+                       seen_xdigits = 0;
                        val = 0;
                        continue;
                }
                if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
                    inet_pton4(curtok, tp) > 0) {
                        tp += NS_INADDRSZ;
-                       saw_xdigit = 0;
+                       seen_xdigits = 0;
                        break;  /* '\0' was seen by inet_pton4(). */
                }
                return (0);
        }
-       if (saw_xdigit) {
+       if (seen_xdigits) {
                if (tp + NS_INT16SZ > endp)
                        return (0);
-               *tp++ = (unsigned char) ((val >> 8) & 0xff);
-               *tp++ = (unsigned char) (val & 0xff);
+               *tp++ = (unsigned char) (val >> 8) & 0xff;
+               *tp++ = (unsigned char) val & 0xff;
        }
        if (colonp != NULL) {
                /*
@@ -211,7 +212,3 @@ inet_pton6(const char *src, unsigned char *dst) {
        memcpy(dst, tmp, NS_IN6ADDRSZ);
        return (1);
 }
-
-#else
-int inet_pton_c_not_empty;
-#endif /* ISC_PLATFORM_NEEDPTON */
diff --git a/lib/isc/iterated_hash.c b/lib/isc/iterated_hash.c
new file mode 100644 (file)
index 0000000..1674314
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006, 2008, 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: iterated_hash.c,v 1.4.48.2 2009/02/18 23:47:12 tbox Exp $ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <isc/sha1.h>
+#include <isc/iterated_hash.h>
+
+int
+isc_iterated_hash(unsigned char out[ISC_SHA1_DIGESTLENGTH],
+                 unsigned int hashalg, int iterations,
+                 const unsigned char *salt, int saltlength,
+                 const unsigned char *in, int inlength)
+{
+       isc_sha1_t ctx;
+       int n = 0;
+
+       if (hashalg != 1)
+               return (0);
+
+       do {
+               isc_sha1_init(&ctx);
+               isc_sha1_update(&ctx, in, inlength);
+               isc_sha1_update(&ctx, salt, saltlength);
+               isc_sha1_final(&ctx, out);
+               in = out;
+               inlength = ISC_SHA1_DIGESTLENGTH;
+       } while (n++ < iterations);
+
+       return (ISC_SHA1_DIGESTLENGTH);
+}
diff --git a/lib/isc/lex.c b/lib/isc/lex.c
new file mode 100644 (file)
index 0000000..8749ed0
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/file.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/parseint.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+typedef struct inputsource {
+       isc_result_t                    result;
+       isc_boolean_t                   is_file;
+       isc_boolean_t                   need_close;
+       isc_boolean_t                   at_eof;
+       isc_buffer_t *                  pushback;
+       unsigned int                    ignored;
+       void *                          input;
+       char *                          name;
+       unsigned long                   line;
+       unsigned long                   saved_line;
+       ISC_LINK(struct inputsource)    link;
+} inputsource;
+
+#define LEX_MAGIC                      ISC_MAGIC('L', 'e', 'x', '!')
+#define VALID_LEX(l)                   ISC_MAGIC_VALID(l, LEX_MAGIC)
+
+struct isc_lex {
+       /* Unlocked. */
+       unsigned int                    magic;
+       isc_mem_t *                     mctx;
+       size_t                          max_token;
+       char *                          data;
+       unsigned int                    comments;
+       isc_boolean_t                   comment_ok;
+       isc_boolean_t                   last_was_eol;
+       unsigned int                    paren_count;
+       unsigned int                    saved_paren_count;
+       isc_lexspecials_t               specials;
+       LIST(struct inputsource)        sources;
+};
+
+static inline isc_result_t
+grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
+       char *new;
+
+       new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
+       if (new == NULL)
+               return (ISC_R_NOMEMORY);
+       memcpy(new, lex->data, lex->max_token + 1);
+       *currp = new + (*currp - lex->data);
+       if (*prevp != NULL)
+               *prevp = new + (*prevp - lex->data);
+       isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
+       lex->data = new;
+       *remainingp += lex->max_token;
+       lex->max_token *= 2;
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
+       isc_lex_t *lex;
+
+       /*
+        * Create a lexer.
+        */
+
+       REQUIRE(lexp != NULL && *lexp == NULL);
+       REQUIRE(max_token > 0U);
+
+       lex = isc_mem_get(mctx, sizeof(*lex));
+       if (lex == NULL)
+               return (ISC_R_NOMEMORY);
+       lex->data = isc_mem_get(mctx, max_token + 1);
+       if (lex->data == NULL) {
+               isc_mem_put(mctx, lex, sizeof(*lex));
+               return (ISC_R_NOMEMORY);
+       }
+       lex->mctx = mctx;
+       lex->max_token = max_token;
+       lex->comments = 0;
+       lex->comment_ok = ISC_TRUE;
+       lex->last_was_eol = ISC_TRUE;
+       lex->paren_count = 0;
+       lex->saved_paren_count = 0;
+       memset(lex->specials, 0, 256);
+       INIT_LIST(lex->sources);
+       lex->magic = LEX_MAGIC;
+
+       *lexp = lex;
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_lex_destroy(isc_lex_t **lexp) {
+       isc_lex_t *lex;
+
+       /*
+        * Destroy the lexer.
+        */
+
+       REQUIRE(lexp != NULL);
+       lex = *lexp;
+       REQUIRE(VALID_LEX(lex));
+
+       while (!EMPTY(lex->sources))
+               RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
+       if (lex->data != NULL)
+               isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
+       lex->magic = 0;
+       isc_mem_put(lex->mctx, lex, sizeof(*lex));
+
+       *lexp = NULL;
+}
+
+unsigned int
+isc_lex_getcomments(isc_lex_t *lex) {
+       /*
+        * Return the current lexer commenting styles.
+        */
+
+       REQUIRE(VALID_LEX(lex));
+
+       return (lex->comments);
+}
+
+void
+isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
+       /*
+        * Set allowed lexer commenting styles.
+        */
+
+       REQUIRE(VALID_LEX(lex));
+
+       lex->comments = comments;
+}
+
+void
+isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
+       /*
+        * Put the current list of specials into 'specials'.
+        */
+
+       REQUIRE(VALID_LEX(lex));
+
+       memcpy(specials, lex->specials, 256);
+}
+
+void
+isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
+       /*
+        * The characters in 'specials' are returned as tokens.  Along with
+        * whitespace, they delimit strings and numbers.
+        */
+
+       REQUIRE(VALID_LEX(lex));
+
+       memcpy(lex->specials, specials, 256);
+}
+
+static inline isc_result_t
+new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close,
+          void *input, const char *name)
+{
+       inputsource *source;
+       isc_result_t result;
+
+       source = isc_mem_get(lex->mctx, sizeof(*source));
+       if (source == NULL)
+               return (ISC_R_NOMEMORY);
+       source->result = ISC_R_SUCCESS;
+       source->is_file = is_file;
+       source->need_close = need_close;
+       source->at_eof = ISC_FALSE;
+       source->input = input;
+       source->name = isc_mem_strdup(lex->mctx, name);
+       if (source->name == NULL) {
+               isc_mem_put(lex->mctx, source, sizeof(*source));
+               return (ISC_R_NOMEMORY);
+       }
+       source->pushback = NULL;
+       result = isc_buffer_allocate(lex->mctx, &source->pushback,
+                                    lex->max_token);
+       if (result != ISC_R_SUCCESS) {
+               isc_mem_free(lex->mctx, source->name);
+               isc_mem_put(lex->mctx, source, sizeof(*source));
+               return (result);
+       }
+       source->ignored = 0;
+       source->line = 1;
+       ISC_LIST_INITANDPREPEND(lex->sources, source, link);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_openfile(isc_lex_t *lex, const char *filename) {
+       isc_result_t result;
+       FILE *stream = NULL;
+
+       /*
+        * Open 'filename' and make it the current input source for 'lex'.
+        */
+
+       REQUIRE(VALID_LEX(lex));
+
+       result = isc_stdio_open(filename, "r", &stream);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
+       if (result != ISC_R_SUCCESS)
+               (void)fclose(stream);
+       return (result);
+}
+
+isc_result_t
+isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
+       char name[128];
+
+       /*
+        * Make 'stream' the current input source for 'lex'.
+        */
+
+       REQUIRE(VALID_LEX(lex));
+
+       snprintf(name, sizeof(name), "stream-%p", stream);
+
+       return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
+}
+
+isc_result_t
+isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
+       char name[128];
+
+       /*
+        * Make 'buffer' the current input source for 'lex'.
+        */
+
+       REQUIRE(VALID_LEX(lex));
+
+       snprintf(name, sizeof(name), "buffer-%p", buffer);
+
+       return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
+}
+
+isc_result_t
+isc_lex_close(isc_lex_t *lex) {
+       inputsource *source;
+
+       /*
+        * Close the most recently opened object (i.e. file or buffer).
+        */
+
+       REQUIRE(VALID_LEX(lex));
+
+       source = HEAD(lex->sources);
+       if (source == NULL)
+               return (ISC_R_NOMORE);
+
+       ISC_LIST_UNLINK(lex->sources, source, link);
+       if (source->is_file) {
+               if (source->need_close)
+                       (void)fclose((FILE *)(source->input));
+       }
+       isc_mem_free(lex->mctx, source->name);
+       isc_buffer_free(&source->pushback);
+       isc_mem_put(lex->mctx, source, sizeof(*source));
+
+       return (ISC_R_SUCCESS);
+}
+
+typedef enum {
+       lexstate_start,
+       lexstate_crlf,
+       lexstate_string,
+       lexstate_number,
+       lexstate_maybecomment,
+       lexstate_ccomment,
+       lexstate_ccommentend,
+       lexstate_eatline,
+       lexstate_qstring
+} lexstate;
+
+#define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
+
+static void
+pushback(inputsource *source, int c) {
+       REQUIRE(source->pushback->current > 0);
+       if (c == EOF) {
+               source->at_eof = ISC_FALSE;
+               return;
+       }
+       source->pushback->current--;
+       if (c == '\n')
+               source->line--;
+}
+
+static isc_result_t
+pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
+       if (isc_buffer_availablelength(source->pushback) == 0) {
+               isc_buffer_t *tbuf = NULL;
+               unsigned int oldlen;
+               isc_region_t used;
+               isc_result_t result;
+
+               oldlen = isc_buffer_length(source->pushback);
+               result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+               isc_buffer_usedregion(source->pushback, &used);
+               result = isc_buffer_copyregion(tbuf, &used);
+               INSIST(result == ISC_R_SUCCESS);
+               tbuf->current = source->pushback->current;
+               isc_buffer_free(&source->pushback);
+               source->pushback = tbuf;
+       }
+       isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
+       inputsource *source;
+       int c;
+       isc_boolean_t done = ISC_FALSE;
+       isc_boolean_t no_comments = ISC_FALSE;
+       isc_boolean_t escaped = ISC_FALSE;
+       lexstate state = lexstate_start;
+       lexstate saved_state = lexstate_start;
+       isc_buffer_t *buffer;
+       FILE *stream;
+       char *curr, *prev;
+       size_t remaining;
+       isc_uint32_t as_ulong;
+       unsigned int saved_options;
+       isc_result_t result;
+
+       /*
+        * Get the next token.
+        */
+
+       REQUIRE(VALID_LEX(lex));
+       source = HEAD(lex->sources);
+       REQUIRE(tokenp != NULL);
+
+       if (source == NULL) {
+               if ((options & ISC_LEXOPT_NOMORE) != 0) {
+                       tokenp->type = isc_tokentype_nomore;
+                       return (ISC_R_SUCCESS);
+               }
+               return (ISC_R_NOMORE);
+       }
+
+       if (source->result != ISC_R_SUCCESS)
+               return (source->result);
+
+       lex->saved_paren_count = lex->paren_count;
+       source->saved_line = source->line;
+
+       if (isc_buffer_remaininglength(source->pushback) == 0 &&
+           source->at_eof)
+       {
+               if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
+                   lex->paren_count != 0) {
+                       lex->paren_count = 0;
+                       return (ISC_R_UNBALANCED);
+               }
+               if ((options & ISC_LEXOPT_EOF) != 0) {
+                       tokenp->type = isc_tokentype_eof;
+                       return (ISC_R_SUCCESS);
+               }
+               return (ISC_R_EOF);
+       }
+
+       isc_buffer_compact(source->pushback);
+
+       saved_options = options;
+       if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
+               options &= ~IWSEOL;
+
+       curr = lex->data;
+       *curr = '\0';
+
+       prev = NULL;
+       remaining = lex->max_token;
+
+#ifdef HAVE_FLOCKFILE
+       if (source->is_file)
+               flockfile(source->input);
+#endif
+
+       do {
+               if (isc_buffer_remaininglength(source->pushback) == 0) {
+                       if (source->is_file) {
+                               stream = source->input;
+
+#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED)
+                               c = getc_unlocked(stream);
+#else
+                               c = getc(stream);
+#endif
+                               if (c == EOF) {
+                                       if (ferror(stream)) {
+                                               source->result = ISC_R_IOERROR;
+                                               result = source->result;
+                                               goto done;
+                                       }
+                                       source->at_eof = ISC_TRUE;
+                               }
+                       } else {
+                               buffer = source->input;
+
+                               if (buffer->current == buffer->used) {
+                                       c = EOF;
+                                       source->at_eof = ISC_TRUE;
+                               } else {
+                                       c = *((char *)buffer->base +
+                                             buffer->current);
+                                       buffer->current++;
+                               }
+                       }
+                       if (c != EOF) {
+                               source->result = pushandgrow(lex, source, c);
+                               if (source->result != ISC_R_SUCCESS) {
+                                       result = source->result;
+                                       goto done;
+                               }
+                       }
+               }
+
+               if (!source->at_eof) {
+                       if (state == lexstate_start)
+                               /* Token has not started yet. */
+                               source->ignored =
+                                  isc_buffer_consumedlength(source->pushback);
+                       c = isc_buffer_getuint8(source->pushback);
+               } else {
+                       c = EOF;
+               }
+
+               if (c == '\n')
+                       source->line++;
+
+               if (lex->comment_ok && !no_comments) {
+                       if (!escaped && c == ';' &&
+                           ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE)
+                            != 0)) {
+                               saved_state = state;
+                               state = lexstate_eatline;
+                               no_comments = ISC_TRUE;
+                               continue;
+                       } else if (c == '/' &&
+                                  (lex->comments &
+                                   (ISC_LEXCOMMENT_C|
+                                    ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
+                               saved_state = state;
+                               state = lexstate_maybecomment;
+                               no_comments = ISC_TRUE;
+                               continue;
+                       } else if (c == '#' &&
+                                  ((lex->comments & ISC_LEXCOMMENT_SHELL)
+                                   != 0)) {
+                               saved_state = state;
+                               state = lexstate_eatline;
+                               no_comments = ISC_TRUE;
+                               continue;
+                       }
+               }
+
+       no_read:
+               /* INSIST(c == EOF || (c >= 0 && c <= 255)); */
+               switch (state) {
+               case lexstate_start:
+                       if (c == EOF) {
+                               lex->last_was_eol = ISC_FALSE;
+                               if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
+                                   lex->paren_count != 0) {
+                                       lex->paren_count = 0;
+                                       result = ISC_R_UNBALANCED;
+                                       goto done;
+                               }
+                               if ((options & ISC_LEXOPT_EOF) == 0) {
+                                       result = ISC_R_EOF;
+                                       goto done;
+                               }
+                               tokenp->type = isc_tokentype_eof;
+                               done = ISC_TRUE;
+                       } else if (c == ' ' || c == '\t') {
+                               if (lex->last_was_eol &&
+                                   (options & ISC_LEXOPT_INITIALWS)
+                                   != 0) {
+                                       lex->last_was_eol = ISC_FALSE;
+                                       tokenp->type = isc_tokentype_initialws;
+                                       tokenp->value.as_char = c;
+                                       done = ISC_TRUE;
+                               }
+                       } else if (c == '\n') {
+                               if ((options & ISC_LEXOPT_EOL) != 0) {
+                                       tokenp->type = isc_tokentype_eol;
+                                       done = ISC_TRUE;
+                               }
+                               lex->last_was_eol = ISC_TRUE;
+                       } else if (c == '\r') {
+                               if ((options & ISC_LEXOPT_EOL) != 0)
+                                       state = lexstate_crlf;
+                       } else if (c == '"' &&
+                                  (options & ISC_LEXOPT_QSTRING) != 0) {
+                               lex->last_was_eol = ISC_FALSE;
+                               no_comments = ISC_TRUE;
+                               state = lexstate_qstring;
+                       } else if (lex->specials[c]) {
+                               lex->last_was_eol = ISC_FALSE;
+                               if ((c == '(' || c == ')') &&
+                                   (options & ISC_LEXOPT_DNSMULTILINE) != 0) {
+                                       if (c == '(') {
+                                               if (lex->paren_count == 0)
+                                                       options &= ~IWSEOL;
+                                               lex->paren_count++;
+                                       } else {
+                                               if (lex->paren_count == 0) {
+                                                   result = ISC_R_UNBALANCED;
+                                                   goto done;
+                                               }
+                                               lex->paren_count--;
+                                               if (lex->paren_count == 0)
+                                                       options =
+                                                               saved_options;
+                                       }
+                                       continue;
+                               }
+                               tokenp->type = isc_tokentype_special;
+                               tokenp->value.as_char = c;
+                               done = ISC_TRUE;
+                       } else if (isdigit((unsigned char)c) &&
+                                  (options & ISC_LEXOPT_NUMBER) != 0) {
+                               lex->last_was_eol = ISC_FALSE;
+                               if ((options & ISC_LEXOPT_OCTAL) != 0 &&
+                                   (c == '8' || c == '9'))
+                                       state = lexstate_string;
+                               else
+                                       state = lexstate_number;
+                               goto no_read;
+                       } else {
+                               lex->last_was_eol = ISC_FALSE;
+                               state = lexstate_string;
+                               goto no_read;
+                       }
+                       break;
+               case lexstate_crlf:
+                       if (c != '\n')
+                               pushback(source, c);
+                       tokenp->type = isc_tokentype_eol;
+                       done = ISC_TRUE;
+                       lex->last_was_eol = ISC_TRUE;
+                       break;
+               case lexstate_number:
+                       if (c == EOF || !isdigit((unsigned char)c)) {
+                               if (c == ' ' || c == '\t' || c == '\r' ||
+                                   c == '\n' || c == EOF ||
+                                   lex->specials[c]) {
+                                       int base;
+                                       if ((options & ISC_LEXOPT_OCTAL) != 0)
+                                               base = 8;
+                                       else if ((options & ISC_LEXOPT_CNUMBER) != 0)
+                                               base = 0;
+                                       else
+                                               base = 10;
+                                       pushback(source, c);
+
+                                       result = isc_parse_uint32(&as_ulong,
+                                                                 lex->data,
+                                                                 base);
+                                       if (result == ISC_R_SUCCESS) {
+                                               tokenp->type =
+                                                       isc_tokentype_number;
+                                               tokenp->value.as_ulong =
+                                                       as_ulong;
+                                       } else if (result == ISC_R_BADNUMBER) {
+                                               isc_tokenvalue_t *v;
+
+                                               tokenp->type =
+                                                       isc_tokentype_string;
+                                               v = &(tokenp->value);
+                                               v->as_textregion.base =
+                                                       lex->data;
+                                               v->as_textregion.length =
+                                                       lex->max_token -
+                                                       remaining;
+                                       } else
+                                               goto done;
+                                       done = ISC_TRUE;
+                                       continue;
+                               } else if (!(options & ISC_LEXOPT_CNUMBER) ||
+                                          ((c != 'x' && c != 'X') ||
+                                          (curr != &lex->data[1]) ||
+                                          (lex->data[0] != '0'))) {
+                                       /* Above test supports hex numbers */
+                                       state = lexstate_string;
+                               }
+                       } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
+                                  (c == '8' || c == '9')) {
+                               state = lexstate_string;
+                       }
+                       if (remaining == 0U) {
+                               result = grow_data(lex, &remaining,
+                                                  &curr, &prev);
+                               if (result != ISC_R_SUCCESS)
+                                       goto done;
+                       }
+                       INSIST(remaining > 0U);
+                       *curr++ = c;
+                       *curr = '\0';
+                       remaining--;
+                       break;
+               case lexstate_string:
+                       /*
+                        * EOF needs to be checked before lex->specials[c]
+                        * as lex->specials[EOF] is not a good idea.
+                        */
+                       if (c == '\r' || c == '\n' || c == EOF ||
+                           (!escaped &&
+                            (c == ' ' || c == '\t' || lex->specials[c]))) {
+                               pushback(source, c);
+                               if (source->result != ISC_R_SUCCESS) {
+                                       result = source->result;
+                                       goto done;
+                               }
+                               tokenp->type = isc_tokentype_string;
+                               tokenp->value.as_textregion.base = lex->data;
+                               tokenp->value.as_textregion.length =
+                                       lex->max_token - remaining;
+                               done = ISC_TRUE;
+                               continue;
+                       }
+                       if ((options & ISC_LEXOPT_ESCAPE) != 0)
+                               escaped = (!escaped && c == '\\') ?
+                                               ISC_TRUE : ISC_FALSE;
+                       if (remaining == 0U) {
+                               result = grow_data(lex, &remaining,
+                                                  &curr, &prev);
+                               if (result != ISC_R_SUCCESS)
+                                       goto done;
+                       }
+                       INSIST(remaining > 0U);
+                       *curr++ = c;
+                       *curr = '\0';
+                       remaining--;
+                       break;
+               case lexstate_maybecomment:
+                       if (c == '*' &&
+                           (lex->comments & ISC_LEXCOMMENT_C) != 0) {
+                               state = lexstate_ccomment;
+                               continue;
+                       } else if (c == '/' &&
+                           (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
+                               state = lexstate_eatline;
+                               continue;
+                       }
+                       pushback(source, c);
+                       c = '/';
+                       no_comments = ISC_FALSE;
+                       state = saved_state;
+                       goto no_read;
+               case lexstate_ccomment:
+                       if (c == EOF) {
+                               result = ISC_R_UNEXPECTEDEND;
+                               goto done;
+                       }
+                       if (c == '*')
+                               state = lexstate_ccommentend;
+                       break;
+               case lexstate_ccommentend:
+                       if (c == EOF) {
+                               result = ISC_R_UNEXPECTEDEND;
+                               goto done;
+                       }
+                       if (c == '/') {
+                               /*
+                                * C-style comments become a single space.
+                                * We do this to ensure that a comment will
+                                * act as a delimiter for strings and
+                                * numbers.
+                                */
+                               c = ' ';
+                               no_comments = ISC_FALSE;
+                               state = saved_state;
+                               goto no_read;
+                       } else if (c != '*')
+                               state = lexstate_ccomment;
+                       break;
+               case lexstate_eatline:
+                       if ((c == '\n') || (c == EOF)) {
+                               no_comments = ISC_FALSE;
+                               state = saved_state;
+                               goto no_read;
+                       }
+                       break;
+               case lexstate_qstring:
+                       if (c == EOF) {
+                               result = ISC_R_UNEXPECTEDEND;
+                               goto done;
+                       }
+                       if (c == '"') {
+                               if (escaped) {
+                                       escaped = ISC_FALSE;
+                                       /*
+                                        * Overwrite the preceding backslash.
+                                        */
+                                       INSIST(prev != NULL);
+                                       *prev = '"';
+                               } else {
+                                       tokenp->type = isc_tokentype_qstring;
+                                       tokenp->value.as_textregion.base =
+                                               lex->data;
+                                       tokenp->value.as_textregion.length =
+                                               lex->max_token - remaining;
+                                       no_comments = ISC_FALSE;
+                                       done = ISC_TRUE;
+                               }
+                       } else {
+                               if (c == '\n' && !escaped &&
+                           (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
+                                       pushback(source, c);
+                                       result = ISC_R_UNBALANCEDQUOTES;
+                                       goto done;
+                               }
+                               if (c == '\\' && !escaped)
+                                       escaped = ISC_TRUE;
+                               else
+                                       escaped = ISC_FALSE;
+                               if (remaining == 0U) {
+                                       result = grow_data(lex, &remaining,
+                                                          &curr, &prev);
+                                       if (result != ISC_R_SUCCESS)
+                                               goto done;
+                               }
+                               INSIST(remaining > 0U);
+                               prev = curr;
+                               *curr++ = c;
+                               *curr = '\0';
+                               remaining--;
+                       }
+                       break;
+               default:
+                       FATAL_ERROR(__FILE__, __LINE__,
+                                   isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
+                                                  ISC_MSG_UNEXPECTEDSTATE,
+                                                  "Unexpected state %d"),
+                                   state);
+                       /* Does not return. */
+               }
+
+       } while (!done);
+
+       result = ISC_R_SUCCESS;
+ done:
+#ifdef HAVE_FLOCKFILE
+       if (source->is_file)
+               funlockfile(source->input);
+#endif
+       return (result);
+}
+
+isc_result_t
+isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
+                      isc_tokentype_t expect, isc_boolean_t eol)
+{
+       unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
+                              ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
+       isc_result_t result;
+
+       if (expect == isc_tokentype_qstring)
+               options |= ISC_LEXOPT_QSTRING;
+       else if (expect == isc_tokentype_number)
+               options |= ISC_LEXOPT_NUMBER;
+       result = isc_lex_gettoken(lex, options, token);
+       if (result == ISC_R_RANGE)
+               isc_lex_ungettoken(lex, token);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       if (eol && ((token->type == isc_tokentype_eol) ||
+                   (token->type == isc_tokentype_eof)))
+               return (ISC_R_SUCCESS);
+       if (token->type == isc_tokentype_string &&
+           expect == isc_tokentype_qstring)
+               return (ISC_R_SUCCESS);
+       if (token->type != expect) {
+               isc_lex_ungettoken(lex, token);
+               if (token->type == isc_tokentype_eol ||
+                   token->type == isc_tokentype_eof)
+                       return (ISC_R_UNEXPECTEDEND);
+               if (expect == isc_tokentype_number)
+                       return (ISC_R_BADNUMBER);
+               return (ISC_R_UNEXPECTEDTOKEN);
+       }
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol)
+{
+       unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
+                              ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE|
+                              ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
+       isc_result_t result;
+
+       result = isc_lex_gettoken(lex, options, token);
+       if (result == ISC_R_RANGE)
+               isc_lex_ungettoken(lex, token);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       if (eol && ((token->type == isc_tokentype_eol) ||
+                   (token->type == isc_tokentype_eof)))
+               return (ISC_R_SUCCESS);
+       if (token->type != isc_tokentype_number) {
+               isc_lex_ungettoken(lex, token);
+               if (token->type == isc_tokentype_eol ||
+                   token->type == isc_tokentype_eof)
+                       return (ISC_R_UNEXPECTEDEND);
+               return (ISC_R_BADNUMBER);
+       }
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
+       inputsource *source;
+       /*
+        * Unget the current token.
+        */
+
+       REQUIRE(VALID_LEX(lex));
+       source = HEAD(lex->sources);
+       REQUIRE(source != NULL);
+       REQUIRE(tokenp != NULL);
+       REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
+               tokenp->type == isc_tokentype_eof);
+
+       UNUSED(tokenp);
+
+       isc_buffer_first(source->pushback);
+       lex->paren_count = lex->saved_paren_count;
+       source->line = source->saved_line;
+       source->at_eof = ISC_FALSE;
+}
+
+void
+isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
+{
+       inputsource *source;
+
+       REQUIRE(VALID_LEX(lex));
+       source = HEAD(lex->sources);
+       REQUIRE(source != NULL);
+       REQUIRE(tokenp != NULL);
+       REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
+               tokenp->type == isc_tokentype_eof);
+
+       UNUSED(tokenp);
+
+       INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
+       r->base = (unsigned char *)isc_buffer_base(source->pushback) +
+                 source->ignored;
+       r->length = isc_buffer_consumedlength(source->pushback) -
+                   source->ignored;
+}
+
+
+char *
+isc_lex_getsourcename(isc_lex_t *lex) {
+       inputsource *source;
+
+       REQUIRE(VALID_LEX(lex));
+       source = HEAD(lex->sources);
+
+       if (source == NULL)
+               return (NULL);
+
+       return (source->name);
+}
+
+unsigned long
+isc_lex_getsourceline(isc_lex_t *lex) {
+       inputsource *source;
+
+       REQUIRE(VALID_LEX(lex));
+       source = HEAD(lex->sources);
+
+       if (source == NULL)
+               return (0);
+
+       return (source->line);
+}
+
+
+isc_result_t
+isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
+       inputsource *source;
+       char *newname;
+
+       REQUIRE(VALID_LEX(lex));
+       source = HEAD(lex->sources);
+
+       if (source == NULL)
+               return(ISC_R_NOTFOUND);
+       newname = isc_mem_strdup(lex->mctx, name);
+       if (newname == NULL)
+               return (ISC_R_NOMEMORY);
+       isc_mem_free(lex->mctx, source->name);
+       source->name = newname;
+       return (ISC_R_SUCCESS);
+}
+
+isc_boolean_t
+isc_lex_isfile(isc_lex_t *lex) {
+       inputsource *source;
+
+       REQUIRE(VALID_LEX(lex));
+
+       source = HEAD(lex->sources);
+
+       if (source == NULL)
+               return (ISC_FALSE);
+
+       return (source->is_file);
+}
diff --git a/lib/isc/lfsr.c b/lib/isc/lfsr.c
new file mode 100644 (file)
index 0000000..0b8d782
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lfsr.c,v 1.20 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <isc/assertions.h>
+#include <isc/lfsr.h>
+#include <isc/util.h>
+
+#define VALID_LFSR(x)  (x != NULL)
+
+void
+isc_lfsr_init(isc_lfsr_t *lfsr, isc_uint32_t state, unsigned int bits,
+             isc_uint32_t tap, unsigned int count,
+             isc_lfsrreseed_t reseed, void *arg)
+{
+       REQUIRE(VALID_LFSR(lfsr));
+       REQUIRE(8 <= bits && bits <= 32);
+       REQUIRE(tap != 0);
+
+       lfsr->state = state;
+       lfsr->bits = bits;
+       lfsr->tap = tap;
+       lfsr->count = count;
+       lfsr->reseed = reseed;
+       lfsr->arg = arg;
+
+       if (count == 0 && reseed != NULL)
+               reseed(lfsr, arg);
+       if (lfsr->state == 0)
+               lfsr->state = 0xffffffffU >> (32 - lfsr->bits);
+}
+
+/*!
+ * Return the next state of the lfsr.
+ */
+static inline isc_uint32_t
+lfsr_generate(isc_lfsr_t *lfsr)
+{
+
+       /*
+        * If the previous state is zero, we must fill it with something
+        * here, or we will begin to generate an extremely predictable output.
+        *
+        * First, give the reseed function a crack at it.  If the state is
+        * still 0, set it to all ones.
+        */
+       if (lfsr->state == 0) {
+               if (lfsr->reseed != NULL)
+                       lfsr->reseed(lfsr, lfsr->arg);
+               if (lfsr->state == 0)
+                       lfsr->state = 0xffffffffU >> (32 - lfsr->bits);
+       }
+
+       if (lfsr->state & 0x01) {
+               lfsr->state = (lfsr->state >> 1) ^ lfsr->tap;
+               return (1);
+       } else {
+               lfsr->state >>= 1;
+               return (0);
+       }
+}
+
+void
+isc_lfsr_generate(isc_lfsr_t *lfsr, void *data, unsigned int count)
+{
+       unsigned char *p;
+       unsigned int bit;
+       unsigned int byte;
+
+       REQUIRE(VALID_LFSR(lfsr));
+       REQUIRE(data != NULL);
+       REQUIRE(count > 0);
+
+       p = data;
+       byte = count;
+
+       while (byte--) {
+               *p = 0;
+               for (bit = 0; bit < 7; bit++) {
+                       *p |= lfsr_generate(lfsr);
+                       *p <<= 1;
+               }
+               *p |= lfsr_generate(lfsr);
+               p++;
+       }
+
+       if (lfsr->count != 0 && lfsr->reseed != NULL) {
+               if (lfsr->count <= count * 8)
+                       lfsr->reseed(lfsr, lfsr->arg);
+               else
+                       lfsr->count -= (count * 8);
+       }
+}
+
+static inline isc_uint32_t
+lfsr_skipgenerate(isc_lfsr_t *lfsr, unsigned int skip)
+{
+       while (skip--)
+               (void)lfsr_generate(lfsr);
+
+       (void)lfsr_generate(lfsr);
+
+       return (lfsr->state);
+}
+
+/*
+ * Skip "skip" states in "lfsr".
+ */
+void
+isc_lfsr_skip(isc_lfsr_t *lfsr, unsigned int skip)
+{
+       REQUIRE(VALID_LFSR(lfsr));
+
+       while (skip--)
+               (void)lfsr_generate(lfsr);
+}
+
+/*
+ * Skip states in lfsr1 and lfsr2 using the other's current state.
+ * Return the final state of lfsr1 ^ lfsr2.
+ */
+isc_uint32_t
+isc_lfsr_generate32(isc_lfsr_t *lfsr1, isc_lfsr_t *lfsr2)
+{
+       isc_uint32_t state1, state2;
+       isc_uint32_t skip1, skip2;
+
+       REQUIRE(VALID_LFSR(lfsr1));
+       REQUIRE(VALID_LFSR(lfsr2));
+
+       skip1 = lfsr1->state & 0x01;
+       skip2 = lfsr2->state & 0x01;
+
+       /* cross-skip. */
+       state1 = lfsr_skipgenerate(lfsr1, skip2);
+       state2 = lfsr_skipgenerate(lfsr2, skip1);
+
+       return (state1 ^ state2);
+}
index 95dd479001a6b08ce531993b6ffa843a082bf3e4..f3a2c2dc790e37f6559ba24bbf6b7f26b3b69286 100644 (file)
@@ -1,21 +1,23 @@
 /*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: lib.c,v 1.9 2001/11/19 03:08:23 mayer Exp $ */
+/* $Id: lib.c,v 1.14 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
 
 #include <config.h>
 
@@ -53,7 +55,7 @@ void
 isc_lib_initmsgcat(void) {
        isc_result_t result;
 
-       /*
+       /*!
         * Initialize the ISC library's message catalog, isc_msgcat, if it
         * has not already been initialized.
         */
index 20d9627057796f413065572906be859ab3d184a1..e19c9ba98eaa973b3cec16b9dcd956453c4dafe2 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004-2006  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: log.c,v 1.84.18.8 2006/03/02 00:37:22 marka Exp $ */
+/* $Id: log.c,v 1.94.332.5 2009/02/16 02:04:05 marka Exp $ */
 
 /*! \file
  * \author  Principal Authors: DCL */
@@ -35,7 +35,6 @@
 #include <isc/magic.h>
 #include <isc/mem.h>
 #include <isc/msgs.h>
-#include <isc/mutex.h>
 #include <isc/print.h>
 #include <isc/stat.h>
 #include <isc/stdio.h>
@@ -62,7 +61,7 @@
  * This is the structure that holds each named channel.  A simple linked
  * list chains all of the channels together, so an individual channel is
  * found by doing strcmp()s with the names down the list.  Their should
- * be no peformance penalty from this as it is expected that the number
+ * be no performance penalty from this as it is expected that the number
  * of named channels will be no more than a dozen or so, and name lookups
  * from the head of the list are only done when isc_log_usechannel() is
  * called, which should also be very infrequent.
@@ -129,7 +128,7 @@ struct isc_logconfig {
  * This isc_log structure provides the context for the isc_log functions.
  * The log context locks itself in isc_log_doit, the internal backend to
  * isc_log_write.  The locking is necessary both to provide exclusive access
- * to the the buffer into which the message is formatted and to guard against
+ * to the buffer into which the message is formatted and to guard against
  * competing threads trying to write to the same syslog resource.  (On
  * some systems, such as BSD/OS, stdio is thread safe but syslog is not.)
  * Unfortunately, the lock cannot guard against a _different_ logging
@@ -205,6 +204,7 @@ LIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = {
        { "time", 0 },
        { "interface", 0 },
        { "timer", 0 },
+       { "file", 0 },
        { NULL, 0 }
 };
 
@@ -1449,7 +1449,7 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
        LOCK(&lctx->lock);
 
        lctx->buffer[0] = '\0';
-       
+
        lcfg = lctx->logconfig;
 
        category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]);
@@ -1508,7 +1508,7 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
                if ((channel->flags & ISC_LOG_PRINTTIME) != 0 &&
                    time_string[0] == '\0') {
                        isc_time_t isctime;
-                       
+
                        TIME_NOW(&isctime);
                        isc_time_formattimestamp(&isctime, time_string,
                                                 sizeof(time_string));
@@ -1519,9 +1519,9 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
                        if (level < ISC_LOG_CRITICAL)
                                snprintf(level_string, sizeof(level_string),
                                         isc_msgcat_get(isc_msgcat,
-                                                       ISC_MSGSET_LOG,
-                                                       ISC_MSG_LEVEL,
-                                                       "level %d: "),
+                                                       ISC_MSGSET_LOG,
+                                                       ISC_MSG_LEVEL,
+                                                       "level %d: "),
                                         level);
                        else if (level > ISC_LOG_DYNAMIC)
                                snprintf(level_string, sizeof(level_string),
@@ -1701,8 +1701,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
                                printcategory ? category->name  : "",
                                printcategory ? ": "            : "",
                                printmodule   ? (module != NULL ? module->name
-                                                               : "no_module")
-                                                               : "",
+                                                               : "no_module")
+                                                               : "",
                                printmodule   ? ": "            : "",
                                printlevel    ? level_string    : "",
                                lctx->buffer);
@@ -1744,8 +1744,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
                               printcategory ? category->name   : "",
                               printcategory ? ": "             : "",
                               printmodule   ? (module != NULL  ? module->name
-                                                               : "no_module")
-                                                               : "",
+                                                               : "no_module")
+                                                               : "",
                               printmodule   ? ": "             : "",
                               printlevel    ? level_string     : "",
                               lctx->buffer);
index f503c84fa0bdaf38bf691cfd019f4a37ecb1d9f3..9c37d7478bdb70f675a5ec425258179d8dc1064b 100644 (file)
 /*
- * this file is leaving the NTP build in favor of
- * inline macros in isc/mem.h for now
- */
-
-/*
- * Copyright (C) 1997-2002  Internet Software Consortium.
+ * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: mem.c,v 1.113 2002/05/23 04:32:30 marka Exp $ */
+/* $Id: mem.c,v 1.145.120.4 2009/02/16 03:17:05 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
 
+#include <limits.h>
+
+#include <isc/magic.h>
 #include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/once.h>
+#include <isc/ondestroy.h>
+#include <isc/string.h>
+#include <isc/mutex.h>
+#include <isc/print.h>
 #include <isc/util.h>
+#include <isc/xml.h>
 
-void *
-isc_mem_get(isc_mem_t *ctx, size_t size) {
-       UNUSED(ctx);
-       if(size == 0)
+#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
+#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
+
+#ifndef ISC_MEM_DEBUGGING
+#define ISC_MEM_DEBUGGING 0
+#endif
+LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
+
+/*
+ * Constants.
+ */
+
+#define DEF_MAX_SIZE           1100
+#define DEF_MEM_TARGET         4096
+#define ALIGNMENT_SIZE         8U              /*%< must be a power of 2 */
+#define NUM_BASIC_BLOCKS       64              /*%< must be > 1 */
+#define TABLE_INCREMENT                1024
+#define DEBUGLIST_COUNT                1024
+
+/*
+ * Types.
+ */
+#if ISC_MEM_TRACKLINES
+typedef struct debuglink debuglink_t;
+struct debuglink {
+       ISC_LINK(debuglink_t)   link;
+       const void             *ptr[DEBUGLIST_COUNT];
+       unsigned int            size[DEBUGLIST_COUNT];
+       const char             *file[DEBUGLIST_COUNT];
+       unsigned int            line[DEBUGLIST_COUNT];
+       unsigned int            count;
+};
+
+#define FLARG_PASS     , file, line
+#define FLARG          , const char *file, int line
+#else
+#define FLARG_PASS
+#define FLARG
+#endif
+
+typedef struct element element;
+struct element {
+       element *               next;
+};
+
+typedef struct {
+       /*!
+        * This structure must be ALIGNMENT_SIZE bytes.
+        */
+       union {
+               size_t          size;
+               isc_mem_t       *ctx;
+               char            bytes[ALIGNMENT_SIZE];
+       } u;
+} size_info;
+
+struct stats {
+       unsigned long           gets;
+       unsigned long           totalgets;
+       unsigned long           blocks;
+       unsigned long           freefrags;
+};
+
+#define MEM_MAGIC              ISC_MAGIC('M', 'e', 'm', 'C')
+#define VALID_CONTEXT(c)       ISC_MAGIC_VALID(c, MEM_MAGIC)
+
+#if ISC_MEM_TRACKLINES
+typedef ISC_LIST(debuglink_t)  debuglist_t;
+#endif
+
+/* List of all active memory contexts. */
+
+static ISC_LIST(isc_mem_t)     contexts;
+static isc_once_t              once = ISC_ONCE_INIT;
+static isc_mutex_t             lock;
+
+/*%
+ * Total size of lost memory due to a bug of external library.
+ * Locked by the global lock.
+ */
+static isc_uint64_t            totallost;
+
+struct isc_mem {
+       unsigned int            magic;
+       isc_ondestroy_t         ondestroy;
+       unsigned int            flags;
+       isc_mutex_t             lock;
+       isc_memalloc_t          memalloc;
+       isc_memfree_t           memfree;
+       void *                  arg;
+       size_t                  max_size;
+       isc_boolean_t           checkfree;
+       struct stats *          stats;
+       unsigned int            references;
+       char                    name[16];
+       void *                  tag;
+       size_t                  quota;
+       size_t                  total;
+       size_t                  inuse;
+       size_t                  maxinuse;
+       size_t                  hi_water;
+       size_t                  lo_water;
+       isc_boolean_t           hi_called;
+       isc_mem_water_t         water;
+       void *                  water_arg;
+       ISC_LIST(isc_mempool_t) pools;
+       unsigned int            poolcnt;
+
+       /*  ISC_MEMFLAG_INTERNAL */
+       size_t                  mem_target;
+       element **              freelists;
+       element *               basic_blocks;
+       unsigned char **        basic_table;
+       unsigned int            basic_table_count;
+       unsigned int            basic_table_size;
+       unsigned char *         lowest;
+       unsigned char *         highest;
+
+#if ISC_MEM_TRACKLINES
+       debuglist_t *           debuglist;
+       unsigned int            debuglistcnt;
+#endif
+
+       unsigned int            memalloc_failures;
+       ISC_LINK(isc_mem_t)     link;
+};
+
+#define MEMPOOL_MAGIC          ISC_MAGIC('M', 'E', 'M', 'p')
+#define VALID_MEMPOOL(c)       ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
+
+struct isc_mempool {
+       /* always unlocked */
+       unsigned int    magic;          /*%< magic number */
+       isc_mutex_t    *lock;           /*%< optional lock */
+       isc_mem_t      *mctx;           /*%< our memory context */
+       /*%< locked via the memory context's lock */
+       ISC_LINK(isc_mempool_t) link;   /*%< next pool in this mem context */
+       /*%< optionally locked from here down */
+       element        *items;          /*%< low water item list */
+       size_t          size;           /*%< size of each item on this pool */
+       unsigned int    maxalloc;       /*%< max number of items allowed */
+       unsigned int    allocated;      /*%< # of items currently given out */
+       unsigned int    freecount;      /*%< # of items on reserved list */
+       unsigned int    freemax;        /*%< # of items allowed on free list */
+       unsigned int    fillcount;      /*%< # of items to fetch on each fill */
+       /*%< Stats only. */
+       unsigned int    gets;           /*%< # of requests to this pool */
+       /*%< Debugging only. */
+#if ISC_MEMPOOL_NAMES
+       char            name[16];       /*%< printed name in stats reports */
+#endif
+};
+
+/*
+ * Private Inline-able.
+ */
+
+#if ! ISC_MEM_TRACKLINES
+#define ADD_TRACE(a, b, c, d, e)
+#define DELETE_TRACE(a, b, c, d, e)
+#else
+#define ADD_TRACE(a, b, c, d, e) \
+       do { \
+               if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
+                                         ISC_MEM_DEBUGRECORD)) != 0 && \
+                    b != NULL) \
+                        add_trace_entry(a, b, c, d, e); \
+       } while (0)
+#define DELETE_TRACE(a, b, c, d, e)    delete_trace_entry(a, b, c, d, e)
+
+static void
+print_active(isc_mem_t *ctx, FILE *out);
+
+/*!
+ * mctx must be locked.
+ */
+static inline void
+add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size
+               FLARG)
+{
+       debuglink_t *dl;
+       unsigned int i;
+
+       if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
+               fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                              ISC_MSG_ADDTRACE,
+                                              "add %p size %u "
+                                              "file %s line %u mctx %p\n"),
+                       ptr, size, file, line, mctx);
+
+       if (mctx->debuglist == NULL)
+               return;
+
+       if (size > mctx->max_size)
+               size = mctx->max_size;
+
+       dl = ISC_LIST_HEAD(mctx->debuglist[size]);
+       while (dl != NULL) {
+               if (dl->count == DEBUGLIST_COUNT)
+                       goto next;
+               for (i = 0; i < DEBUGLIST_COUNT; i++) {
+                       if (dl->ptr[i] == NULL) {
+                               dl->ptr[i] = ptr;
+                               dl->size[i] = size;
+                               dl->file[i] = file;
+                               dl->line[i] = line;
+                               dl->count++;
+                               return;
+                       }
+               }
+       next:
+               dl = ISC_LIST_NEXT(dl, link);
+       }
+
+       dl = malloc(sizeof(debuglink_t));
+       INSIST(dl != NULL);
+
+       ISC_LINK_INIT(dl, link);
+       for (i = 1; i < DEBUGLIST_COUNT; i++) {
+               dl->ptr[i] = NULL;
+               dl->size[i] = 0;
+               dl->file[i] = NULL;
+               dl->line[i] = 0;
+       }
+
+       dl->ptr[0] = ptr;
+       dl->size[0] = size;
+       dl->file[0] = file;
+       dl->line[0] = line;
+       dl->count = 1;
+
+       ISC_LIST_PREPEND(mctx->debuglist[size], dl, link);
+       mctx->debuglistcnt++;
+}
+
+static inline void
+delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size,
+                  const char *file, unsigned int line)
+{
+       debuglink_t *dl;
+       unsigned int i;
+
+       if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
+               fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                              ISC_MSG_DELTRACE,
+                                              "del %p size %u "
+                                              "file %s line %u mctx %p\n"),
+                       ptr, size, file, line, mctx);
+
+       if (mctx->debuglist == NULL)
+               return;
+
+       if (size > mctx->max_size)
+               size = mctx->max_size;
+
+       dl = ISC_LIST_HEAD(mctx->debuglist[size]);
+       while (dl != NULL) {
+               for (i = 0; i < DEBUGLIST_COUNT; i++) {
+                       if (dl->ptr[i] == ptr) {
+                               dl->ptr[i] = NULL;
+                               dl->size[i] = 0;
+                               dl->file[i] = NULL;
+                               dl->line[i] = 0;
+
+                               INSIST(dl->count > 0);
+                               dl->count--;
+                               if (dl->count == 0) {
+                                       ISC_LIST_UNLINK(mctx->debuglist[size],
+                                                       dl, link);
+                                       free(dl);
+                               }
+                               return;
+                       }
+               }
+               dl = ISC_LIST_NEXT(dl, link);
+       }
+
+       /*
+        * If we get here, we didn't find the item on the list.  We're
+        * screwed.
+        */
+       INSIST(dl != NULL);
+}
+#endif /* ISC_MEM_TRACKLINES */
+
+static inline size_t
+rmsize(size_t size) {
+       /*
+        * round down to ALIGNMENT_SIZE
+        */
+       return (size & (~(ALIGNMENT_SIZE - 1)));
+}
+
+static inline size_t
+quantize(size_t size) {
+       /*!
+        * Round up the result in order to get a size big
+        * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
+        * byte boundaries.
+        */
+
+       if (size == 0U)
+               return (ALIGNMENT_SIZE);
+       return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
+}
+
+static inline isc_boolean_t
+more_basic_blocks(isc_mem_t *ctx) {
+       void *new;
+       unsigned char *curr, *next;
+       unsigned char *first, *last;
+       unsigned char **table;
+       unsigned int table_size;
+       size_t increment;
+       int i;
+
+       /* Require: we hold the context lock. */
+
+       /*
+        * Did we hit the quota for this context?
+        */
+       increment = NUM_BASIC_BLOCKS * ctx->mem_target;
+       if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
+               return (ISC_FALSE);
+
+       INSIST(ctx->basic_table_count <= ctx->basic_table_size);
+       if (ctx->basic_table_count == ctx->basic_table_size) {
+               table_size = ctx->basic_table_size + TABLE_INCREMENT;
+               table = (ctx->memalloc)(ctx->arg,
+                                       table_size * sizeof(unsigned char *));
+               if (table == NULL) {
+                       ctx->memalloc_failures++;
+                       return (ISC_FALSE);
+               }
+               if (ctx->basic_table_size != 0) {
+                       memcpy(table, ctx->basic_table,
+                              ctx->basic_table_size *
+                              sizeof(unsigned char *));
+                       (ctx->memfree)(ctx->arg, ctx->basic_table);
+               }
+               ctx->basic_table = table;
+               ctx->basic_table_size = table_size;
+       }
+
+       new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
+       if (new == NULL) {
+               ctx->memalloc_failures++;
+               return (ISC_FALSE);
+       }
+       ctx->total += increment;
+       ctx->basic_table[ctx->basic_table_count] = new;
+       ctx->basic_table_count++;
+
+       curr = new;
+       next = curr + ctx->mem_target;
+       for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
+               ((element *)curr)->next = (element *)next;
+               curr = next;
+               next += ctx->mem_target;
+       }
+       /*
+        * curr is now pointing at the last block in the
+        * array.
+        */
+       ((element *)curr)->next = NULL;
+       first = new;
+       last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
+       if (first < ctx->lowest || ctx->lowest == NULL)
+               ctx->lowest = first;
+       if (last > ctx->highest)
+               ctx->highest = last;
+       ctx->basic_blocks = new;
+
+       return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+more_frags(isc_mem_t *ctx, size_t new_size) {
+       int i, frags;
+       size_t total_size;
+       void *new;
+       unsigned char *curr, *next;
+
+       /*!
+        * Try to get more fragments by chopping up a basic block.
+        */
+
+       if (ctx->basic_blocks == NULL) {
+               if (!more_basic_blocks(ctx)) {
+                       /*
+                        * We can't get more memory from the OS, or we've
+                        * hit the quota for this context.
+                        */
+                       /*
+                        * XXXRTH  "At quota" notification here.
+                        */
+                       return (ISC_FALSE);
+               }
+       }
+
+       total_size = ctx->mem_target;
+       new = ctx->basic_blocks;
+       ctx->basic_blocks = ctx->basic_blocks->next;
+       frags = total_size / new_size;
+       ctx->stats[new_size].blocks++;
+       ctx->stats[new_size].freefrags += frags;
+       /*
+        * Set up a linked-list of blocks of size
+        * "new_size".
+        */
+       curr = new;
+       next = curr + new_size;
+       total_size -= new_size;
+       for (i = 0; i < (frags - 1); i++) {
+               ((element *)curr)->next = (element *)next;
+               curr = next;
+               next += new_size;
+               total_size -= new_size;
+       }
+       /*
+        * Add the remaining fragment of the basic block to a free list.
+        */
+       total_size = rmsize(total_size);
+       if (total_size > 0U) {
+               ((element *)next)->next = ctx->freelists[total_size];
+               ctx->freelists[total_size] = (element *)next;
+               ctx->stats[total_size].freefrags++;
+       }
+       /*
+        * curr is now pointing at the last block in the
+        * array.
+        */
+       ((element *)curr)->next = NULL;
+       ctx->freelists[new_size] = new;
+
+       return (ISC_TRUE);
+}
+
+static inline void *
+mem_getunlocked(isc_mem_t *ctx, size_t size) {
+       size_t new_size = quantize(size);
+       void *ret;
+
+       if (size >= ctx->max_size || new_size >= ctx->max_size) {
+               /*
+                * memget() was called on something beyond our upper limit.
+                */
+               if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
+                       ret = NULL;
+                       goto done;
+               }
+               ret = (ctx->memalloc)(ctx->arg, size);
+               if (ret == NULL) {
+                       ctx->memalloc_failures++;
+                       goto done;
+               }
+               ctx->total += size;
+               ctx->inuse += size;
+               ctx->stats[ctx->max_size].gets++;
+               ctx->stats[ctx->max_size].totalgets++;
+               /*
+                * If we don't set new_size to size, then the
+                * ISC_MEM_FILL code might write over bytes we
+                * don't own.
+                */
+               new_size = size;
+               goto done;
+       }
+
+       /*
+        * If there are no blocks in the free list for this size, get a chunk
+        * of memory and then break it up into "new_size"-sized blocks, adding
+        * them to the free list.
+        */
+       if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
+               return (NULL);
+
+       /*
+        * The free list uses the "rounded-up" size "new_size".
+        */
+       ret = ctx->freelists[new_size];
+       ctx->freelists[new_size] = ctx->freelists[new_size]->next;
+
+       /*
+        * The stats[] uses the _actual_ "size" requested by the
+        * caller, with the caveat (in the code above) that "size" >= the
+        * max. size (max_size) ends up getting recorded as a call to
+        * max_size.
+        */
+       ctx->stats[size].gets++;
+       ctx->stats[size].totalgets++;
+       ctx->stats[new_size].freefrags--;
+       ctx->inuse += new_size;
+
+ done:
+
+#if ISC_MEM_FILL
+       if (ret != NULL)
+               memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
+#endif
+
+       return (ret);
+}
+
+#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
+static inline void
+check_overrun(void *mem, size_t size, size_t new_size) {
+       unsigned char *cp;
+
+       cp = (unsigned char *)mem;
+       cp += size;
+       while (size < new_size) {
+               INSIST(*cp == 0xbe);
+               cp++;
+               size++;
+       }
+}
+#endif
+
+static inline void
+mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) {
+       size_t new_size = quantize(size);
+
+       if (size == ctx->max_size || new_size >= ctx->max_size) {
+               /*
+                * memput() called on something beyond our upper limit.
+                */
+#if ISC_MEM_FILL
+               memset(mem, 0xde, size); /* Mnemonic for "dead". */
+#endif
+               (ctx->memfree)(ctx->arg, mem);
+               INSIST(ctx->stats[ctx->max_size].gets != 0U);
+               ctx->stats[ctx->max_size].gets--;
+               INSIST(size <= ctx->total);
+               ctx->inuse -= size;
+               ctx->total -= size;
+               return;
+       }
+
+#if ISC_MEM_FILL
+#if ISC_MEM_CHECKOVERRUN
+       check_overrun(mem, size, new_size);
+#endif
+       memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
+#endif
+
+       /*
+        * The free list uses the "rounded-up" size "new_size".
+        */
+       ((element *)mem)->next = ctx->freelists[new_size];
+       ctx->freelists[new_size] = (element *)mem;
+
+       /*
+        * The stats[] uses the _actual_ "size" requested by the
+        * caller, with the caveat (in the code above) that "size" >= the
+        * max. size (max_size) ends up getting recorded as a call to
+        * max_size.
+        */
+       INSIST(ctx->stats[size].gets != 0U);
+       ctx->stats[size].gets--;
+       ctx->stats[new_size].freefrags++;
+       ctx->inuse -= new_size;
+}
+
+/*!
+ * Perform a malloc, doing memory filling and overrun detection as necessary.
+ */
+static inline void *
+mem_get(isc_mem_t *ctx, size_t size) {
+       char *ret;
+
+#if ISC_MEM_CHECKOVERRUN
+       size += 1;
+#endif
+
+       ret = (ctx->memalloc)(ctx->arg, size);
+       if (ret == NULL)
+               ctx->memalloc_failures++;
+
+#if ISC_MEM_FILL
+       if (ret != NULL)
+               memset(ret, 0xbe, size); /* Mnemonic for "beef". */
+#else
+#  if ISC_MEM_CHECKOVERRUN
+       if (ret != NULL)
+               ret[size-1] = 0xbe;
+#  endif
+#endif
+
+       return (ret);
+}
+
+/*!
+ * Perform a free, doing memory filling and overrun detection as necessary.
+ */
+static inline void
+mem_put(isc_mem_t *ctx, void *mem, size_t size) {
+#if ISC_MEM_CHECKOVERRUN
+       INSIST(((unsigned char *)mem)[size] == 0xbe);
+#endif
+#if ISC_MEM_FILL
+       memset(mem, 0xde, size); /* Mnemonic for "dead". */
+#else
+       UNUSED(size);
+#endif
+       (ctx->memfree)(ctx->arg, mem);
+}
+
+/*!
+ * Update internal counters after a memory get.
+ */
+static inline void
+mem_getstats(isc_mem_t *ctx, size_t size) {
+       ctx->total += size;
+       ctx->inuse += size;
+
+       if (size > ctx->max_size) {
+               ctx->stats[ctx->max_size].gets++;
+               ctx->stats[ctx->max_size].totalgets++;
+       } else {
+               ctx->stats[size].gets++;
+               ctx->stats[size].totalgets++;
+       }
+}
+
+/*!
+ * Update internal counters after a memory put.
+ */
+static inline void
+mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) {
+       UNUSED(ptr);
+
+       INSIST(ctx->inuse >= size);
+       ctx->inuse -= size;
+
+       if (size > ctx->max_size) {
+               INSIST(ctx->stats[ctx->max_size].gets > 0U);
+               ctx->stats[ctx->max_size].gets--;
+       } else {
+               INSIST(ctx->stats[size].gets > 0U);
+               ctx->stats[size].gets--;
+       }
+}
+
+/*
+ * Private.
+ */
+
+static void *
+default_memalloc(void *arg, size_t size) {
+       UNUSED(arg);
+       if (size == 0U)
                size = 1;
        return (malloc(size));
 }
 
+static void
+default_memfree(void *arg, void *ptr) {
+       UNUSED(arg);
+       free(ptr);
+}
+
+static void
+initialize_action(void) {
+       RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
+       ISC_LIST_INIT(contexts);
+       totallost = 0;
+}
+
+/*
+ * Public.
+ */
+
+isc_result_t
+isc_mem_createx(size_t init_max_size, size_t target_size,
+               isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
+               isc_mem_t **ctxp)
+{
+       return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
+                                arg, ctxp, ISC_MEMFLAG_DEFAULT));
+
+}
+
+isc_result_t
+isc_mem_createx2(size_t init_max_size, size_t target_size,
+                isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
+                isc_mem_t **ctxp, unsigned int flags)
+{
+       isc_mem_t *ctx;
+       isc_result_t result;
+
+       REQUIRE(ctxp != NULL && *ctxp == NULL);
+       REQUIRE(memalloc != NULL);
+       REQUIRE(memfree != NULL);
+
+       INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
+
+       RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+       ctx = (memalloc)(arg, sizeof(*ctx));
+       if (ctx == NULL)
+               return (ISC_R_NOMEMORY);
+
+       if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
+               result = isc_mutex_init(&ctx->lock);
+               if (result != ISC_R_SUCCESS) {
+                       (memfree)(arg, ctx);
+                       return (result);
+               }
+       }
+
+       if (init_max_size == 0U)
+               ctx->max_size = DEF_MAX_SIZE;
+       else
+               ctx->max_size = init_max_size;
+       ctx->flags = flags;
+       ctx->references = 1;
+       memset(ctx->name, 0, sizeof(ctx->name));
+       ctx->tag = NULL;
+       ctx->quota = 0;
+       ctx->total = 0;
+       ctx->inuse = 0;
+       ctx->maxinuse = 0;
+       ctx->hi_water = 0;
+       ctx->lo_water = 0;
+       ctx->hi_called = ISC_FALSE;
+       ctx->water = NULL;
+       ctx->water_arg = NULL;
+       ctx->magic = MEM_MAGIC;
+       isc_ondestroy_init(&ctx->ondestroy);
+       ctx->memalloc = memalloc;
+       ctx->memfree = memfree;
+       ctx->arg = arg;
+       ctx->stats = NULL;
+       ctx->checkfree = ISC_TRUE;
+#if ISC_MEM_TRACKLINES
+       ctx->debuglist = NULL;
+       ctx->debuglistcnt = 0;
+#endif
+       ISC_LIST_INIT(ctx->pools);
+       ctx->poolcnt = 0;
+       ctx->freelists = NULL;
+       ctx->basic_blocks = NULL;
+       ctx->basic_table = NULL;
+       ctx->basic_table_count = 0;
+       ctx->basic_table_size = 0;
+       ctx->lowest = NULL;
+       ctx->highest = NULL;
+
+       ctx->stats = (memalloc)(arg,
+                               (ctx->max_size+1) * sizeof(struct stats));
+       if (ctx->stats == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto error;
+       }
+       memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
+
+       if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
+               if (target_size == 0U)
+                       ctx->mem_target = DEF_MEM_TARGET;
+               else
+                       ctx->mem_target = target_size;
+               ctx->freelists = (memalloc)(arg, ctx->max_size *
+                                                sizeof(element *));
+               if (ctx->freelists == NULL) {
+                       result = ISC_R_NOMEMORY;
+                       goto error;
+               }
+               memset(ctx->freelists, 0,
+                      ctx->max_size * sizeof(element *));
+       }
+
+#if ISC_MEM_TRACKLINES
+       if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
+               unsigned int i;
+
+               ctx->debuglist = (memalloc)(arg,
+                                     (ctx->max_size+1) * sizeof(debuglist_t));
+               if (ctx->debuglist == NULL) {
+                       result = ISC_R_NOMEMORY;
+                       goto error;
+               }
+               for (i = 0; i <= ctx->max_size; i++)
+                       ISC_LIST_INIT(ctx->debuglist[i]);
+       }
+#endif
+
+       ctx->memalloc_failures = 0;
+
+       LOCK(&lock);
+       ISC_LIST_INITANDAPPEND(contexts, ctx, link);
+       UNLOCK(&lock);
+
+       *ctxp = ctx;
+       return (ISC_R_SUCCESS);
+
+  error:
+       if (ctx != NULL) {
+               if (ctx->stats != NULL)
+                       (memfree)(arg, ctx->stats);
+               if (ctx->freelists != NULL)
+                       (memfree)(arg, ctx->freelists);
+#if ISC_MEM_TRACKLINES
+               if (ctx->debuglist != NULL)
+                       (ctx->memfree)(ctx->arg, ctx->debuglist);
+#endif /* ISC_MEM_TRACKLINES */
+               if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
+                       DESTROYLOCK(&ctx->lock);
+               (memfree)(arg, ctx);
+       }
+
+       return (result);
+}
+
+isc_result_t
+isc_mem_create(size_t init_max_size, size_t target_size,
+              isc_mem_t **ctxp)
+{
+       return (isc_mem_createx2(init_max_size, target_size,
+                                default_memalloc, default_memfree, NULL,
+                                ctxp, ISC_MEMFLAG_DEFAULT));
+}
+
+isc_result_t
+isc_mem_create2(size_t init_max_size, size_t target_size,
+               isc_mem_t **ctxp, unsigned int flags)
+{
+       return (isc_mem_createx2(init_max_size, target_size,
+                                default_memalloc, default_memfree, NULL,
+                                ctxp, flags));
+}
+
+static void
+destroy(isc_mem_t *ctx) {
+       unsigned int i;
+       isc_ondestroy_t ondest;
+
+       ctx->magic = 0;
+
+       LOCK(&lock);
+       ISC_LIST_UNLINK(contexts, ctx, link);
+       totallost += ctx->inuse;
+       UNLOCK(&lock);
+
+       INSIST(ISC_LIST_EMPTY(ctx->pools));
+
+#if ISC_MEM_TRACKLINES
+       if (ctx->debuglist != NULL) {
+               if (ctx->checkfree) {
+                       for (i = 0; i <= ctx->max_size; i++) {
+                               if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
+                                       print_active(ctx, stderr);
+                               INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
+                       }
+               } else {
+                       debuglink_t *dl;
+
+                       for (i = 0; i <= ctx->max_size; i++)
+                               for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
+                                    dl != NULL;
+                                    dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
+                                       ISC_LIST_UNLINK(ctx->debuglist[i],
+                                                       dl, link);
+                                       free(dl);
+                               }
+               }
+               (ctx->memfree)(ctx->arg, ctx->debuglist);
+       }
+#endif
+       INSIST(ctx->references == 0);
+
+       if (ctx->checkfree) {
+               for (i = 0; i <= ctx->max_size; i++) {
+#if ISC_MEM_TRACKLINES
+                       if (ctx->stats[i].gets != 0U)
+                               print_active(ctx, stderr);
+#endif
+                       INSIST(ctx->stats[i].gets == 0U);
+               }
+       }
+
+       (ctx->memfree)(ctx->arg, ctx->stats);
+
+       if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+               for (i = 0; i < ctx->basic_table_count; i++)
+                       (ctx->memfree)(ctx->arg, ctx->basic_table[i]);
+               (ctx->memfree)(ctx->arg, ctx->freelists);
+               if (ctx->basic_table != NULL)
+                       (ctx->memfree)(ctx->arg, ctx->basic_table);
+       }
+
+       ondest = ctx->ondestroy;
+
+       if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
+               DESTROYLOCK(&ctx->lock);
+       (ctx->memfree)(ctx->arg, ctx);
+
+       isc_ondestroy_notify(&ondest, ctx);
+}
+
+void
+isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
+       REQUIRE(VALID_CONTEXT(source));
+       REQUIRE(targetp != NULL && *targetp == NULL);
+
+       MCTXLOCK(source, &source->lock);
+       source->references++;
+       MCTXUNLOCK(source, &source->lock);
+
+       *targetp = source;
+}
+
+void
+isc_mem_detach(isc_mem_t **ctxp) {
+       isc_mem_t *ctx;
+       isc_boolean_t want_destroy = ISC_FALSE;
+
+       REQUIRE(ctxp != NULL);
+       ctx = *ctxp;
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       MCTXLOCK(ctx, &ctx->lock);
+       INSIST(ctx->references > 0);
+       ctx->references--;
+       if (ctx->references == 0)
+               want_destroy = ISC_TRUE;
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       if (want_destroy)
+               destroy(ctx);
+
+       *ctxp = NULL;
+}
+
+/*
+ * isc_mem_putanddetach() is the equivalent of:
+ *
+ * mctx = NULL;
+ * isc_mem_attach(ptr->mctx, &mctx);
+ * isc_mem_detach(&ptr->mctx);
+ * isc_mem_put(mctx, ptr, sizeof(*ptr);
+ * isc_mem_detach(&mctx);
+ */
+
+void
+isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
+       isc_mem_t *ctx;
+       isc_boolean_t want_destroy = ISC_FALSE;
+       size_info *si;
+       size_t oldsize;
+
+       REQUIRE(ctxp != NULL);
+       ctx = *ctxp;
+       REQUIRE(VALID_CONTEXT(ctx));
+       REQUIRE(ptr != NULL);
+
+       /*
+        * Must be before mem_putunlocked() as ctxp is usually within
+        * [ptr..ptr+size).
+        */
+       *ctxp = NULL;
+
+       if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
+               if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
+                       si = &(((size_info *)ptr)[-1]);
+                       oldsize = si->u.size - ALIGNMENT_SIZE;
+                       if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
+                               oldsize -= ALIGNMENT_SIZE;
+                       INSIST(oldsize == size);
+               }
+               isc__mem_free(ctx, ptr FLARG_PASS);
+
+               MCTXLOCK(ctx, &ctx->lock);
+               ctx->references--;
+               if (ctx->references == 0)
+                       want_destroy = ISC_TRUE;
+               MCTXUNLOCK(ctx, &ctx->lock);
+               if (want_destroy)
+                       destroy(ctx);
+
+               return;
+       }
+
+       if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+               MCTXLOCK(ctx, &ctx->lock);
+               mem_putunlocked(ctx, ptr, size);
+       } else {
+               mem_put(ctx, ptr, size);
+               MCTXLOCK(ctx, &ctx->lock);
+               mem_putstats(ctx, ptr, size);
+       }
+
+       DELETE_TRACE(ctx, ptr, size, file, line);
+       INSIST(ctx->references > 0);
+       ctx->references--;
+       if (ctx->references == 0)
+               want_destroy = ISC_TRUE;
+
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       if (want_destroy)
+               destroy(ctx);
+}
+
+void
+isc_mem_destroy(isc_mem_t **ctxp) {
+       isc_mem_t *ctx;
+
+       /*
+        * This routine provides legacy support for callers who use mctxs
+        * without attaching/detaching.
+        */
+
+       REQUIRE(ctxp != NULL);
+       ctx = *ctxp;
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       MCTXLOCK(ctx, &ctx->lock);
+#if ISC_MEM_TRACKLINES
+       if (ctx->references != 1)
+               print_active(ctx, stderr);
+#endif
+       REQUIRE(ctx->references == 1);
+       ctx->references--;
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       destroy(ctx);
+
+       *ctxp = NULL;
+}
+
+isc_result_t
+isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
+       isc_result_t res;
+
+       MCTXLOCK(ctx, &ctx->lock);
+       res = isc_ondestroy_register(&ctx->ondestroy, task, event);
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       return (res);
+}
+
+
+void *
+isc__mem_get(isc_mem_t *ctx, size_t size FLARG) {
+       void *ptr;
+       isc_boolean_t call_water = ISC_FALSE;
+
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
+               return (isc__mem_allocate(ctx, size FLARG_PASS));
+
+       if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+               MCTXLOCK(ctx, &ctx->lock);
+               ptr = mem_getunlocked(ctx, size);
+       } else {
+               ptr = mem_get(ctx, size);
+               MCTXLOCK(ctx, &ctx->lock);
+               if (ptr != NULL)
+                       mem_getstats(ctx, size);
+       }
+
+       ADD_TRACE(ctx, ptr, size, file, line);
+       if (ctx->hi_water != 0U && !ctx->hi_called &&
+           ctx->inuse > ctx->hi_water) {
+               call_water = ISC_TRUE;
+       }
+       if (ctx->inuse > ctx->maxinuse) {
+               ctx->maxinuse = ctx->inuse;
+               if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
+                   (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
+                       fprintf(stderr, "maxinuse = %lu\n",
+                               (unsigned long)ctx->inuse);
+       }
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       if (call_water)
+               (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
+
+       return (ptr);
+}
+
+void
+isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG)
+{
+       isc_boolean_t call_water = ISC_FALSE;
+       size_info *si;
+       size_t oldsize;
+
+       REQUIRE(VALID_CONTEXT(ctx));
+       REQUIRE(ptr != NULL);
+
+       if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
+               if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
+                       si = &(((size_info *)ptr)[-1]);
+                       oldsize = si->u.size - ALIGNMENT_SIZE;
+                       if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
+                               oldsize -= ALIGNMENT_SIZE;
+                       INSIST(oldsize == size);
+               }
+               isc__mem_free(ctx, ptr FLARG_PASS);
+               return;
+       }
+
+       if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+               MCTXLOCK(ctx, &ctx->lock);
+               mem_putunlocked(ctx, ptr, size);
+       } else {
+               mem_put(ctx, ptr, size);
+               MCTXLOCK(ctx, &ctx->lock);
+               mem_putstats(ctx, ptr, size);
+       }
+
+       DELETE_TRACE(ctx, ptr, size, file, line);
+
+       /*
+        * The check against ctx->lo_water == 0 is for the condition
+        * when the context was pushed over hi_water but then had
+        * isc_mem_setwater() called with 0 for hi_water and lo_water.
+        */
+       if (ctx->hi_called &&
+           (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
+               if (ctx->water != NULL)
+                       call_water = ISC_TRUE;
+       }
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       if (call_water)
+               (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
+}
+
+void
+isc_mem_waterack(isc_mem_t *ctx, int flag) {
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       MCTXLOCK(ctx, &ctx->lock);
+       if (flag == ISC_MEM_LOWATER)
+               ctx->hi_called = ISC_FALSE;
+       else if (flag == ISC_MEM_HIWATER)
+               ctx->hi_called = ISC_TRUE;
+       MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+#if ISC_MEM_TRACKLINES
+static void
+print_active(isc_mem_t *mctx, FILE *out) {
+       if (mctx->debuglist != NULL) {
+               debuglink_t *dl;
+               unsigned int i, j;
+               const char *format;
+               isc_boolean_t found;
+
+               fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                           ISC_MSG_DUMPALLOC,
+                                           "Dump of all outstanding "
+                                           "memory allocations:\n"));
+               found = ISC_FALSE;
+               format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                       ISC_MSG_PTRFILELINE,
+                                       "\tptr %p size %u file %s line %u\n");
+               for (i = 0; i <= mctx->max_size; i++) {
+                       dl = ISC_LIST_HEAD(mctx->debuglist[i]);
+
+                       if (dl != NULL)
+                               found = ISC_TRUE;
+
+                       while (dl != NULL) {
+                               for (j = 0; j < DEBUGLIST_COUNT; j++)
+                                       if (dl->ptr[j] != NULL)
+                                               fprintf(out, format,
+                                                       dl->ptr[j],
+                                                       dl->size[j],
+                                                       dl->file[j],
+                                                       dl->line[j]);
+                               dl = ISC_LIST_NEXT(dl, link);
+                       }
+               }
+               if (!found)
+                       fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                                   ISC_MSG_NONE, "\tNone.\n"));
+       }
+}
+#endif
+
+/*
+ * Print the stats[] on the stream "out" with suitable formatting.
+ */
+void
+isc_mem_stats(isc_mem_t *ctx, FILE *out) {
+       size_t i;
+       const struct stats *s;
+       const isc_mempool_t *pool;
+
+       REQUIRE(VALID_CONTEXT(ctx));
+       MCTXLOCK(ctx, &ctx->lock);
+
+       for (i = 0; i <= ctx->max_size; i++) {
+               s = &ctx->stats[i];
+
+               if (s->totalgets == 0U && s->gets == 0U)
+                       continue;
+               fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
+                       (i == ctx->max_size) ? ">=" : "  ",
+                       (unsigned long) i, s->totalgets, s->gets);
+               if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
+                   (s->blocks != 0U || s->freefrags != 0U))
+                       fprintf(out, " (%lu bl, %lu ff)",
+                               s->blocks, s->freefrags);
+               fputc('\n', out);
+       }
+
+       /*
+        * Note that since a pool can be locked now, these stats might be
+        * somewhat off if the pool is in active use at the time the stats
+        * are dumped.  The link fields are protected by the isc_mem_t's
+        * lock, however, so walking this list and extracting integers from
+        * stats fields is always safe.
+        */
+       pool = ISC_LIST_HEAD(ctx->pools);
+       if (pool != NULL) {
+               fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                           ISC_MSG_POOLSTATS,
+                                           "[Pool statistics]\n"));
+               fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
+                       isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                      ISC_MSG_POOLNAME, "name"),
+                       isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                      ISC_MSG_POOLSIZE, "size"),
+                       isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                      ISC_MSG_POOLMAXALLOC, "maxalloc"),
+                       isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                      ISC_MSG_POOLALLOCATED, "allocated"),
+                       isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                      ISC_MSG_POOLFREECOUNT, "freecount"),
+                       isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                      ISC_MSG_POOLFREEMAX, "freemax"),
+                       isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                      ISC_MSG_POOLFILLCOUNT, "fillcount"),
+                       isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
+                                      ISC_MSG_POOLGETS, "gets"),
+                       "L");
+       }
+       while (pool != NULL) {
+               fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
+                       pool->name, (unsigned long) pool->size, pool->maxalloc,
+                       pool->allocated, pool->freecount, pool->freemax,
+                       pool->fillcount, pool->gets,
+                       (pool->lock == NULL ? "N" : "Y"));
+               pool = ISC_LIST_NEXT(pool, link);
+       }
+
+#if ISC_MEM_TRACKLINES
+       print_active(ctx, out);
+#endif
+
+       MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+/*
+ * Replacements for malloc() and free() -- they implicitly remember the
+ * size of the object allocated (with some additional overhead).
+ */
+
+static void *
+isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) {
+       size_info *si;
+
+       size += ALIGNMENT_SIZE;
+       if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
+               size += ALIGNMENT_SIZE;
+
+       if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
+               si = mem_getunlocked(ctx, size);
+       else
+               si = mem_get(ctx, size);
+
+       if (si == NULL)
+               return (NULL);
+       if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
+               si->u.ctx = ctx;
+               si++;
+       }
+       si->u.size = size;
+       return (&si[1]);
+}
+
+void *
+isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) {
+       size_info *si;
+       isc_boolean_t call_water = ISC_FALSE;
+
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+               MCTXLOCK(ctx, &ctx->lock);
+               si = isc__mem_allocateunlocked(ctx, size);
+       } else {
+               si = isc__mem_allocateunlocked(ctx, size);
+               MCTXLOCK(ctx, &ctx->lock);
+               if (si != NULL)
+                       mem_getstats(ctx, si[-1].u.size);
+       }
+
+#if ISC_MEM_TRACKLINES
+       ADD_TRACE(ctx, si, si[-1].u.size, file, line);
+#endif
+       if (ctx->hi_water != 0U && !ctx->hi_called &&
+           ctx->inuse > ctx->hi_water) {
+               ctx->hi_called = ISC_TRUE;
+               call_water = ISC_TRUE;
+       }
+       if (ctx->inuse > ctx->maxinuse) {
+               ctx->maxinuse = ctx->inuse;
+               if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
+                   (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
+                       fprintf(stderr, "maxinuse = %lu\n",
+                               (unsigned long)ctx->inuse);
+       }
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       if (call_water)
+               (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
+
+       return (si);
+}
+
+void *
+isc__mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG) {
+       void *new_ptr = NULL;
+       size_t oldsize, copysize;
+
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       /*
+        * This function emulates the realloc(3) standard library function:
+        * - if size > 0, allocate new memory; and if ptr is non NULL, copy
+        *   as much of the old contents to the new buffer and free the old one.
+        *   Note that when allocation fails the original pointer is intact;
+        *   the caller must free it.
+        * - if size is 0 and ptr is non NULL, simply free the given ptr.
+        * - this function returns:
+        *     pointer to the newly allocated memory, or
+        *     NULL if allocation fails or doesn't happen.
+        */
+       if (size > 0U) {
+               new_ptr = isc__mem_allocate(ctx, size FLARG_PASS);
+               if (new_ptr != NULL && ptr != NULL) {
+                       oldsize = (((size_info *)ptr)[-1]).u.size;
+                       INSIST(oldsize >= ALIGNMENT_SIZE);
+                       oldsize -= ALIGNMENT_SIZE;
+                       copysize = oldsize > size ? size : oldsize;
+                       memcpy(new_ptr, ptr, copysize);
+                       isc__mem_free(ctx, ptr FLARG_PASS);
+               }
+       } else if (ptr != NULL)
+               isc__mem_free(ctx, ptr FLARG_PASS);
+
+       return (new_ptr);
+}
+
+void
+isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) {
+       size_info *si;
+       size_t size;
+       isc_boolean_t call_water= ISC_FALSE;
+
+       REQUIRE(VALID_CONTEXT(ctx));
+       REQUIRE(ptr != NULL);
+
+       if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
+               si = &(((size_info *)ptr)[-2]);
+               REQUIRE(si->u.ctx == ctx);
+               size = si[1].u.size;
+       } else {
+               si = &(((size_info *)ptr)[-1]);
+               size = si->u.size;
+       }
+
+       if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+               MCTXLOCK(ctx, &ctx->lock);
+               mem_putunlocked(ctx, si, size);
+       } else {
+               mem_put(ctx, si, size);
+               MCTXLOCK(ctx, &ctx->lock);
+               mem_putstats(ctx, si, size);
+       }
+
+       DELETE_TRACE(ctx, ptr, size, file, line);
+
+       /*
+        * The check against ctx->lo_water == 0 is for the condition
+        * when the context was pushed over hi_water but then had
+        * isc_mem_setwater() called with 0 for hi_water and lo_water.
+        */
+       if (ctx->hi_called &&
+           (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
+               ctx->hi_called = ISC_FALSE;
+
+               if (ctx->water != NULL)
+                       call_water = ISC_TRUE;
+       }
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       if (call_water)
+               (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
+}
+
+
+/*
+ * Other useful things.
+ */
+
+char *
+isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
+       size_t len;
+       char *ns;
+
+       REQUIRE(VALID_CONTEXT(mctx));
+       REQUIRE(s != NULL);
+
+       len = strlen(s);
+
+       ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS);
+
+       if (ns != NULL)
+               strncpy(ns, s, len + 1);
+
+       return (ns);
+}
+
+void
+isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
+       REQUIRE(VALID_CONTEXT(ctx));
+       MCTXLOCK(ctx, &ctx->lock);
+
+       ctx->checkfree = flag;
+
+       MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+/*
+ * Quotas
+ */
+
+void
+isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
+       REQUIRE(VALID_CONTEXT(ctx));
+       MCTXLOCK(ctx, &ctx->lock);
+
+       ctx->quota = quota;
+
+       MCTXUNLOCK(ctx, &ctx->lock);
+}
+
+size_t
+isc_mem_getquota(isc_mem_t *ctx) {
+       size_t quota;
+
+       REQUIRE(VALID_CONTEXT(ctx));
+       MCTXLOCK(ctx, &ctx->lock);
+
+       quota = ctx->quota;
+
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       return (quota);
+}
+
+size_t
+isc_mem_inuse(isc_mem_t *ctx) {
+       size_t inuse;
+
+       REQUIRE(VALID_CONTEXT(ctx));
+       MCTXLOCK(ctx, &ctx->lock);
+
+       inuse = ctx->inuse;
+
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       return (inuse);
+}
+
 void
-isc_mem_put(isc_mem_t *ctx, void *ptr, size_t size)
+isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
+                size_t hiwater, size_t lowater)
 {
+       isc_boolean_t callwater = ISC_FALSE;
+       isc_mem_water_t oldwater;
+       void *oldwater_arg;
+
+       REQUIRE(VALID_CONTEXT(ctx));
+       REQUIRE(hiwater >= lowater);
+
+       MCTXLOCK(ctx, &ctx->lock);
+       oldwater = ctx->water;
+       oldwater_arg = ctx->water_arg;
+       if (water == NULL) {
+               callwater = ctx->hi_called;
+               ctx->water = NULL;
+               ctx->water_arg = NULL;
+               ctx->hi_water = 0;
+               ctx->lo_water = 0;
+               ctx->hi_called = ISC_FALSE;
+       } else {
+               if (ctx->hi_called &&
+                   (ctx->water != water || ctx->water_arg != water_arg ||
+                    ctx->inuse < lowater || lowater == 0U))
+                       callwater = ISC_TRUE;
+               ctx->water = water;
+               ctx->water_arg = water_arg;
+               ctx->hi_water = hiwater;
+               ctx->lo_water = lowater;
+               ctx->hi_called = ISC_FALSE;
+       }
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       if (callwater && oldwater != NULL)
+               (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
+}
+
+void
+isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) {
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       LOCK(&ctx->lock);
+       memset(ctx->name, 0, sizeof(ctx->name));
+       strncpy(ctx->name, name, sizeof(ctx->name) - 1);
+       ctx->tag = tag;
+       UNLOCK(&ctx->lock);
+}
+
+const char *
+isc_mem_getname(isc_mem_t *ctx) {
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       return (ctx->name);
+}
+
+void *
+isc_mem_gettag(isc_mem_t *ctx) {
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       return (ctx->tag);
+}
+
+/*
+ * Memory pool stuff
+ */
+
+isc_result_t
+isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
+       isc_mempool_t *mpctx;
+
+       REQUIRE(VALID_CONTEXT(mctx));
+       REQUIRE(size > 0U);
+       REQUIRE(mpctxp != NULL && *mpctxp == NULL);
+
+       /*
+        * Allocate space for this pool, initialize values, and if all works
+        * well, attach to the memory context.
+        */
+       mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
+       if (mpctx == NULL)
+               return (ISC_R_NOMEMORY);
+
+       mpctx->magic = MEMPOOL_MAGIC;
+       mpctx->lock = NULL;
+       mpctx->mctx = mctx;
+       mpctx->size = size;
+       mpctx->maxalloc = UINT_MAX;
+       mpctx->allocated = 0;
+       mpctx->freecount = 0;
+       mpctx->freemax = 1;
+       mpctx->fillcount = 1;
+       mpctx->gets = 0;
+#if ISC_MEMPOOL_NAMES
+       mpctx->name[0] = 0;
+#endif
+       mpctx->items = NULL;
+
+       *mpctxp = mpctx;
+
+       MCTXLOCK(mctx, &mctx->lock);
+       ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
+       mctx->poolcnt++;
+       MCTXUNLOCK(mctx, &mctx->lock);
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
+       REQUIRE(name != NULL);
+
+#if ISC_MEMPOOL_NAMES
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
+       mpctx->name[sizeof(mpctx->name) - 1] = '\0';
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+#else
+       UNUSED(mpctx);
+       UNUSED(name);
+#endif
+}
+
+void
+isc_mempool_destroy(isc_mempool_t **mpctxp) {
+       isc_mempool_t *mpctx;
+       isc_mem_t *mctx;
+       isc_mutex_t *lock;
+       element *item;
+
+       REQUIRE(mpctxp != NULL);
+       mpctx = *mpctxp;
+       REQUIRE(VALID_MEMPOOL(mpctx));
+#if ISC_MEMPOOL_NAMES
+       if (mpctx->allocated > 0)
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_mempool_destroy(): mempool %s "
+                                "leaked memory",
+                                mpctx->name);
+#endif
+       REQUIRE(mpctx->allocated == 0);
+
+       mctx = mpctx->mctx;
+
+       lock = mpctx->lock;
+
+       if (lock != NULL)
+               LOCK(lock);
+
+       /*
+        * Return any items on the free list
+        */
+       MCTXLOCK(mctx, &mctx->lock);
+       while (mpctx->items != NULL) {
+               INSIST(mpctx->freecount > 0);
+               mpctx->freecount--;
+               item = mpctx->items;
+               mpctx->items = item->next;
+
+               if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+                       mem_putunlocked(mctx, item, mpctx->size);
+               } else {
+                       mem_put(mctx, item, mpctx->size);
+                       mem_putstats(mctx, item, mpctx->size);
+               }
+       }
+       MCTXUNLOCK(mctx, &mctx->lock);
+
+       /*
+        * Remove our linked list entry from the memory context.
+        */
+       MCTXLOCK(mctx, &mctx->lock);
+       ISC_LIST_UNLINK(mctx->pools, mpctx, link);
+       mctx->poolcnt--;
+       MCTXUNLOCK(mctx, &mctx->lock);
+
+       mpctx->magic = 0;
+
+       isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t));
+
+       if (lock != NULL)
+               UNLOCK(lock);
+
+       *mpctxp = NULL;
+}
+
+void
+isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
+       REQUIRE(VALID_MEMPOOL(mpctx));
+       REQUIRE(mpctx->lock == NULL);
+       REQUIRE(lock != NULL);
+
+       mpctx->lock = lock;
+}
+
+void *
+isc__mempool_get(isc_mempool_t *mpctx FLARG) {
+       element *item;
+       isc_mem_t *mctx;
+       unsigned int i;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       mctx = mpctx->mctx;
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       /*
+        * Don't let the caller go over quota
+        */
+       if (mpctx->allocated >= mpctx->maxalloc) {
+               item = NULL;
+               goto out;
+       }
+
+       /*
+        * if we have a free list item, return the first here
+        */
+       item = mpctx->items;
+       if (item != NULL) {
+               mpctx->items = item->next;
+               INSIST(mpctx->freecount > 0);
+               mpctx->freecount--;
+               mpctx->gets++;
+               mpctx->allocated++;
+               goto out;
+       }
+
+       /*
+        * We need to dip into the well.  Lock the memory context here and
+        * fill up our free list.
+        */
+       MCTXLOCK(mctx, &mctx->lock);
+       for (i = 0; i < mpctx->fillcount; i++) {
+               if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+                       item = mem_getunlocked(mctx, mpctx->size);
+               } else {
+                       item = mem_get(mctx, mpctx->size);
+                       if (item != NULL)
+                               mem_getstats(mctx, mpctx->size);
+               }
+               if (item == NULL)
+                       break;
+               item->next = mpctx->items;
+               mpctx->items = item;
+               mpctx->freecount++;
+       }
+       MCTXUNLOCK(mctx, &mctx->lock);
+
+       /*
+        * If we didn't get any items, return NULL.
+        */
+       item = mpctx->items;
+       if (item == NULL)
+               goto out;
+
+       mpctx->items = item->next;
+       mpctx->freecount--;
+       mpctx->gets++;
+       mpctx->allocated++;
+
+ out:
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+#if ISC_MEM_TRACKLINES
+       if (item != NULL) {
+               MCTXLOCK(mctx, &mctx->lock);
+               ADD_TRACE(mctx, item, mpctx->size, file, line);
+               MCTXUNLOCK(mctx, &mctx->lock);
+       }
+#endif /* ISC_MEM_TRACKLINES */
+
+       return (item);
+}
+
+void
+isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
+       isc_mem_t *mctx;
+       element *item;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+       REQUIRE(mem != NULL);
+
+       mctx = mpctx->mctx;
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       INSIST(mpctx->allocated > 0);
+       mpctx->allocated--;
+
+#if ISC_MEM_TRACKLINES
+       MCTXLOCK(mctx, &mctx->lock);
+       DELETE_TRACE(mctx, mem, mpctx->size, file, line);
+       MCTXUNLOCK(mctx, &mctx->lock);
+#endif /* ISC_MEM_TRACKLINES */
+
+       /*
+        * If our free list is full, return this to the mctx directly.
+        */
+       if (mpctx->freecount >= mpctx->freemax) {
+               if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+                       MCTXLOCK(mctx, &mctx->lock);
+                       mem_putunlocked(mctx, mem, mpctx->size);
+                       MCTXUNLOCK(mctx, &mctx->lock);
+               } else {
+                       mem_put(mctx, mem, mpctx->size);
+                       MCTXLOCK(mctx, &mctx->lock);
+                       mem_putstats(mctx, mem, mpctx->size);
+                       MCTXUNLOCK(mctx, &mctx->lock);
+               }
+               if (mpctx->lock != NULL)
+                       UNLOCK(mpctx->lock);
+               return;
+       }
+
+       /*
+        * Otherwise, attach it to our free list and bump the counter.
+        */
+       mpctx->freecount++;
+       item = (element *)mem;
+       item->next = mpctx->items;
+       mpctx->items = item;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+}
+
+/*
+ * Quotas
+ */
+
+void
+isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       mpctx->freemax = limit;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+}
+
+unsigned int
+isc_mempool_getfreemax(isc_mempool_t *mpctx) {
+       unsigned int freemax;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       freemax = mpctx->freemax;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (freemax);
+}
+
+unsigned int
+isc_mempool_getfreecount(isc_mempool_t *mpctx) {
+       unsigned int freecount;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       freecount = mpctx->freecount;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (freecount);
+}
+
+void
+isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
+       REQUIRE(limit > 0);
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       mpctx->maxalloc = limit;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+}
+
+unsigned int
+isc_mempool_getmaxalloc(isc_mempool_t *mpctx) {
+       unsigned int maxalloc;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       maxalloc = mpctx->maxalloc;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (maxalloc);
+}
+
+unsigned int
+isc_mempool_getallocated(isc_mempool_t *mpctx) {
+       unsigned int allocated;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       allocated = mpctx->allocated;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (allocated);
+}
+
+void
+isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
+       REQUIRE(limit > 0);
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       mpctx->fillcount = limit;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+}
+
+unsigned int
+isc_mempool_getfillcount(isc_mempool_t *mpctx) {
+       unsigned int fillcount;
+
+       REQUIRE(VALID_MEMPOOL(mpctx));
+
+       if (mpctx->lock != NULL)
+               LOCK(mpctx->lock);
+
+       fillcount = mpctx->fillcount;
+
+       if (mpctx->lock != NULL)
+               UNLOCK(mpctx->lock);
+
+       return (fillcount);
+}
+
+void
+isc_mem_printactive(isc_mem_t *ctx, FILE *file) {
+
+       REQUIRE(VALID_CONTEXT(ctx));
+       REQUIRE(file != NULL);
+
+#if !ISC_MEM_TRACKLINES
        UNUSED(ctx);
-       UNUSED(size);
-       free(ptr);
+       UNUSED(file);
+#else
+       print_active(ctx, file);
+#endif
+}
+
+void
+isc_mem_printallactive(FILE *file) {
+#if !ISC_MEM_TRACKLINES
+       UNUSED(file);
+#else
+       isc_mem_t *ctx;
+
+       RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+       LOCK(&lock);
+       for (ctx = ISC_LIST_HEAD(contexts);
+            ctx != NULL;
+            ctx = ISC_LIST_NEXT(ctx, link)) {
+               fprintf(file, "context: %p\n", ctx);
+               print_active(ctx, file);
+       }
+       UNLOCK(&lock);
+#endif
+}
+
+void
+isc_mem_checkdestroyed(FILE *file) {
+
+       RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+       LOCK(&lock);
+       if (!ISC_LIST_EMPTY(contexts))  {
+#if ISC_MEM_TRACKLINES
+               isc_mem_t *ctx;
+
+               for (ctx = ISC_LIST_HEAD(contexts);
+                    ctx != NULL;
+                    ctx = ISC_LIST_NEXT(ctx, link)) {
+                       fprintf(file, "context: %p\n", ctx);
+                       print_active(ctx, file);
+               }
+               fflush(file);
+#endif
+               INSIST(0);
+       }
+       UNLOCK(&lock);
+}
+
+unsigned int
+isc_mem_references(isc_mem_t *ctx) {
+       unsigned int references;
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       MCTXLOCK(ctx, &ctx->lock);
+       references = ctx->references;
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       return (references);
+}
+
+#ifdef HAVE_LIBXML2
+
+typedef struct summarystat {
+       isc_uint64_t    total;
+       isc_uint64_t    inuse;
+       isc_uint64_t    blocksize;
+       isc_uint64_t    contextsize;
+} summarystat_t;
+
+static void
+renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
+       REQUIRE(VALID_CONTEXT(ctx));
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "context");
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
+       xmlTextWriterWriteFormatString(writer, "%p", ctx);
+       xmlTextWriterEndElement(writer); /* id */
+
+       if (ctx->name[0] != 0) {
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
+               xmlTextWriterWriteFormatString(writer, "%s", ctx->name);
+               xmlTextWriterEndElement(writer); /* name */
+       }
+
+       REQUIRE(VALID_CONTEXT(ctx));
+       MCTXLOCK(ctx, &ctx->lock);
+
+       summary->contextsize += sizeof(*ctx) +
+               (ctx->max_size + 1) * sizeof(struct stats) +
+               ctx->max_size * sizeof(element *) +
+               ctx->basic_table_count * sizeof(char *);
+#if ISC_MEM_TRACKLINES
+       if (ctx->debuglist != NULL) {
+               summary->contextsize +=
+                       (ctx->max_size + 1) * sizeof(debuglist_t) +
+                       ctx->debuglistcnt * sizeof(debuglink_t);
+       }
+#endif
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
+       xmlTextWriterWriteFormatString(writer, "%d", ctx->references);
+       xmlTextWriterEndElement(writer); /* references */
+
+       summary->total += ctx->total;
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "total");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      (isc_uint64_t)ctx->total);
+       xmlTextWriterEndElement(writer); /* total */
+
+       summary->inuse += ctx->inuse;
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      (isc_uint64_t)ctx->inuse);
+       xmlTextWriterEndElement(writer); /* inuse */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      (isc_uint64_t)ctx->maxinuse);
+       xmlTextWriterEndElement(writer); /* maxinuse */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize");
+       if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
+               summary->blocksize += ctx->basic_table_count *
+                       NUM_BASIC_BLOCKS * ctx->mem_target;
+               xmlTextWriterWriteFormatString(writer,
+                                              "%" ISC_PRINT_QUADFORMAT "u",
+                                              (isc_uint64_t)
+                                              ctx->basic_table_count *
+                                              NUM_BASIC_BLOCKS *
+                                              ctx->mem_target);
+       } else
+               xmlTextWriterWriteFormatString(writer, "%s", "-");
+       xmlTextWriterEndElement(writer); /* blocksize */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools");
+       xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt);
+       xmlTextWriterEndElement(writer); /* pools */
+       summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      (isc_uint64_t)ctx->hi_water);
+       xmlTextWriterEndElement(writer); /* hiwater */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      (isc_uint64_t)ctx->lo_water);
+       xmlTextWriterEndElement(writer); /* lowater */
+
+       MCTXUNLOCK(ctx, &ctx->lock);
+
+       xmlTextWriterEndElement(writer); /* context */
+}
+
+void
+isc_mem_renderxml(xmlTextWriterPtr writer) {
+       isc_mem_t *ctx;
+       summarystat_t summary;
+       isc_uint64_t lost;
+
+       memset(&summary, 0, sizeof(summary));
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts");
+
+       RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+
+       LOCK(&lock);
+       lost = totallost;
+       for (ctx = ISC_LIST_HEAD(contexts);
+            ctx != NULL;
+            ctx = ISC_LIST_NEXT(ctx, link)) {
+               renderctx(ctx, &summary, writer);
+       }
+       UNLOCK(&lock);
+
+       xmlTextWriterEndElement(writer); /* contexts */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary");
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      summary.total);
+       xmlTextWriterEndElement(writer); /* TotalUse */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      summary.inuse);
+       xmlTextWriterEndElement(writer); /* InUse */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      summary.blocksize);
+       xmlTextWriterEndElement(writer); /* BlockSize */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      summary.contextsize);
+       xmlTextWriterEndElement(writer); /* ContextSize */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost");
+       xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u",
+                                      lost);
+       xmlTextWriterEndElement(writer); /* Lost */
+
+       xmlTextWriterEndElement(writer); /* summary */
 }
 
+#endif /* HAVE_LIBXML2 */
diff --git a/lib/isc/mips/include/isc/atomic.h b/lib/isc/mips/include/isc/atomic.h
new file mode 100644 (file)
index 0000000..bb739f7
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.3 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, int val) {
+       isc_int32_t orig;
+
+       /* add is a cheat, since MIPS has no mov instruction */
+       __asm__ volatile (
+           "1:"
+           "ll $3, %1\n"
+           "add %0, $0, $3\n"
+           "add $3, $3, %2\n"
+           "sc $3, %1\n"
+           "beq $3, 0, 1b"
+           : "=&r"(orig)
+           : "m"(*p), "r"(val)
+           : "memory", "$3"
+               );
+
+       return (orig);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+       __asm__ volatile (
+           "1:"
+           "ll $3, %0\n"
+           "add $3, $0, %1\n"
+           "sc $3, %0\n"
+           "beq $3, 0, 1b"
+           :
+           : "m"(*p), "r"(val)
+           : "memory", "$3"
+               );
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'.  The original value is returned in any
+ * case.
+ */
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, int cmpval, int val) {
+       isc_int32_t orig;
+
+       __asm__ volatile(
+           "1:"
+           "ll $3, %1\n"
+           "add %0, $0, $3\n"
+           "bne $3, %2, 2f\n"
+           "add $3, $0, %3\n"
+           "sc $3, %1\n"
+           "beq $3, 0, 1b\n"
+           "2:"
+           : "=&r"(orig)
+           : "m"(*p), "r"(cmpval), "r"(val)
+           : "memory", "$3"
+               );
+
+       return (orig);
+}
+
+#else /* !ISC_PLATFORM_USEGCCASM */
+
+#error "unsupported compiler.  disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/mutexblock.c b/lib/isc/mutexblock.c
new file mode 100644 (file)
index 0000000..d45ad0e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: mutexblock.c,v 1.20 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mutexblock.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_mutexblock_init(isc_mutex_t *block, unsigned int count) {
+       isc_result_t result;
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               result = isc_mutex_init(&block[i]);
+               if (result != ISC_R_SUCCESS) {
+                       i--;
+                       while (i > 0) {
+                               DESTROYLOCK(&block[i]);
+                               i--;
+                       }
+                       return (result);
+               }
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_mutexblock_destroy(isc_mutex_t *block, unsigned int count) {
+       isc_result_t result;
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               result = isc_mutex_destroy(&block[i]);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+       }
+
+       return (ISC_R_SUCCESS);
+}
index 1fcd1027b39dd37945c1bf0ab97b7819c7e26511..85dd53e03eb6b883ccfe73213910ca8882bd9a9c 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: netaddr.c,v 1.18.12.9 2004/05/15 03:46:12 jinmei Exp $ */
+/* $Id: netaddr.c,v 1.38 2007/06/18 23:47:44 tbox Exp $ */
 
-#include <config.h>
+/*! \file */
 
-#define ISC_ONLY_IPV6
+#include <config.h>
 
 #include <stdio.h>
 
@@ -53,6 +53,12 @@ isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
                    a->zone != b->zone)
                        return (ISC_FALSE);
                break;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+       case AF_UNIX:
+               if (strcmp(a->type.un, b->type.un) != 0)
+                       return (ISC_FALSE);
+               break;
+#endif
        default:
                return (ISC_FALSE);
        }
@@ -73,7 +79,7 @@ isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
        if (a->family != b->family)
                return (ISC_FALSE);
 
-       if (a->zone != b->zone)
+       if (a->zone != b->zone && b->zone != 0)
                return (ISC_FALSE);
 
        switch (a->family) {
@@ -137,6 +143,16 @@ isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
        case AF_INET6:
                type = &netaddr->type.in6;
                break;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+       case AF_UNIX:
+               alen = strlen(netaddr->type.un);
+               if (alen > isc_buffer_availablelength(target))
+                       return (ISC_R_NOSPACE);
+               isc_buffer_putmem(target,
+                                 (const unsigned char *)(netaddr->type.un),
+                                 alen);
+               return (ISC_R_SUCCESS);
+#endif
        default:
                return (ISC_R_FAILURE);
        }
@@ -192,6 +208,42 @@ isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
        }
 }
 
+
+isc_result_t
+isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
+       static const unsigned char zeros[16];
+       unsigned int nbits, nbytes, ipbytes;
+       const unsigned char *p;
+
+       switch (na->family) {
+       case AF_INET:
+               p = (const unsigned char *) &na->type.in;
+               ipbytes = 4;
+               if (prefixlen > 32)
+                       return (ISC_R_RANGE);
+               break;
+       case AF_INET6:
+               p = (const unsigned char *) &na->type.in6;
+               ipbytes = 16;
+               if (prefixlen > 128)
+                       return (ISC_R_RANGE);
+               break;
+       default:
+               ipbytes = 0;
+               return (ISC_R_NOTIMPLEMENTED);
+       }
+       nbytes = prefixlen / 8;
+       nbits = prefixlen % 8;
+       if (nbits != 0) {
+               if ((p[nbytes] & (0xff>>nbits)) != 0U)
+                       return (ISC_R_FAILURE);
+               nbytes++;
+       }
+       if (memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0)
+               return (ISC_R_FAILURE);
+       return (ISC_R_SUCCESS);
+}
+
 isc_result_t
 isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
        unsigned int nbits, nbytes, ipbytes, i;
@@ -248,6 +300,25 @@ isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
        netaddr->type.in6 = *ina6;
 }
 
+isc_result_t
+isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
+#ifdef ISC_PLATFORM_HAVESYSUNH
+        if (strlen(path) > sizeof(netaddr->type.un) - 1)
+                return (ISC_R_NOSPACE);
+
+        memset(netaddr, 0, sizeof(*netaddr));
+        netaddr->family = AF_UNIX;
+        strcpy(netaddr->type.un, path);
+        netaddr->zone = 0;
+        return (ISC_R_SUCCESS);
+#else 
+       UNUSED(netaddr);
+       UNUSED(path);
+        return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+
 void
 isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) {
        /* we currently only support AF_INET6. */
@@ -278,6 +349,12 @@ isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
                t->zone = 0;
 #endif
                break;
+#ifdef ISC_PLATFORM_HAVESYSUNH
+       case AF_UNIX:
+               memcpy(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
+               t->zone = 0;
+               break;
+#endif
        default:
                INSIST(0);
        }
@@ -290,14 +367,12 @@ isc_netaddr_any(isc_netaddr_t *netaddr) {
        netaddr->type.in.s_addr = INADDR_ANY;
 }
 
-#ifdef ISC_PLATFORM_HAVEIPV6
 void
 isc_netaddr_any6(isc_netaddr_t *netaddr) {
        memset(netaddr, 0, sizeof(*netaddr));
        netaddr->family = AF_INET6;
        netaddr->type.in6 = in6addr_any;
 }
-#endif
 
 isc_boolean_t
 isc_netaddr_ismulticast(isc_netaddr_t *na) {
@@ -345,7 +420,6 @@ isc_netaddr_issitelocal(isc_netaddr_t *na) {
        }
 }
 
-#ifdef ISC_PLATFORM_HAVEIPV6
 void
 isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
        isc_netaddr_t *src;
@@ -360,4 +434,3 @@ isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
        memcpy(&t->type.in, (char *)&src->type.in6 + 12, 4);
        return;
 }
-#endif
index f0bffc44a457ee7813b7c71f33a2f5b9be398a9b..9aa11db9a8cef490a4f6e2835f2196e53768271e 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
+/*! \file */
+
 #if defined(LIBC_SCCS) && !defined(lint)
 static char rcsid[] =
-       "$Id: netscope.c,v 1.5.142.7 2004/03/12 10:31:26 marka Exp $";
+       "$Id: netscope.c,v 1.13 2007/06/19 23:47:17 tbox Exp $";
 #endif /* LIBC_SCCS and not lint */
 
 #include <config.h>
index 8253a0613b2115297d2a3602a74458835cfee270..3d6b6764d5822dba75a644a7e14b36bad271920e 100644 (file)
@@ -1,30 +1,31 @@
 /*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: msgcat.c,v 1.12 2001/11/30 01:59:39 gson Exp $ */
+/* $Id: msgcat.c,v 1.18 2007/06/19 23:47:18 tbox Exp $ */
 
-/*
- * Principal Author: Bob Halley
+/*! \file msgcat.c
+ *
+ * \author Principal Author: Bob Halley
  */
 
 #include <config.h>
 
+#include <stddef.h>
 #include <stdlib.h>
-#include <unistd.h>
 
 #include <isc/magic.h>
 #include <isc/msgcat.h>
diff --git a/lib/isc/noatomic/include/isc/atomic.h b/lib/isc/noatomic/include/isc/atomic.h
new file mode 100644 (file)
index 0000000..942ba03
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.4 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+/* This file is inherently empty. */
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/nothreads/condition.c b/lib/isc/nothreads/condition.c
new file mode 100644 (file)
index 0000000..9be8f83
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2004, 2006, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: condition.c,v 1.10 2007/06/19 23:47:18 tbox Exp $ */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
diff --git a/lib/isc/nothreads/include/isc/condition.h b/lib/isc/nothreads/include/isc/condition.h
new file mode 100644 (file)
index 0000000..b269f82
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: condition.h,v 1.6 2007/06/19 23:47:18 tbox Exp $ */
+
+/*
+ * This provides a limited subset of the isc_condition_t
+ * functionality for use by single-threaded programs that
+ * need to block waiting for events.   Only a single
+ * call to isc_condition_wait() may be blocked at any given
+ * time, and the _waituntil and _broadcast functions are not
+ * supported.  This is intended primarily for use by the omapi
+ * library, and may go away once omapi goes away.  Use for
+ * other purposes is strongly discouraged.
+ */
+
+#ifndef ISC_CONDITION_H
+#define ISC_CONDITION_H 1
+
+#include <isc/mutex.h>
+
+typedef int isc_condition_t;
+
+isc_result_t isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp);
+isc_result_t isc__nothread_signal_hack(isc_condition_t *cp);
+
+#define isc_condition_init(cp) \
+       (*(cp) = 0, ISC_R_SUCCESS)
+
+#define isc_condition_wait(cp, mp) \
+       isc__nothread_wait_hack(cp, mp)
+
+#define isc_condition_waituntil(cp, mp, tp) \
+       ((void)(cp), (void)(mp), (void)(tp), ISC_R_NOTIMPLEMENTED)
+
+#define isc_condition_signal(cp) \
+       isc__nothread_signal_hack(cp)
+
+#define isc_condition_broadcast(cp) \
+       ((void)(cp), ISC_R_NOTIMPLEMENTED)
+
+#define isc_condition_destroy(cp) \
+       (*(cp) == 0 ? (*(cp) = -1, ISC_R_SUCCESS) : ISC_R_UNEXPECTED)
+
+#endif /* ISC_CONDITION_H */
diff --git a/lib/isc/nothreads/include/isc/mutex.h b/lib/isc/nothreads/include/isc/mutex.h
new file mode 100644 (file)
index 0000000..1f2187b
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: mutex.h,v 1.6 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_MUTEX_H
+#define ISC_MUTEX_H 1
+
+#include <isc/result.h>                /* for ISC_R_ codes */
+
+typedef int isc_mutex_t;
+
+#define isc_mutex_init(mp) \
+       (*(mp) = 0, ISC_R_SUCCESS)
+#define isc_mutex_lock(mp) \
+       ((*(mp))++ == 0 ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#define isc_mutex_unlock(mp) \
+       (--(*(mp)) == 0 ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#define isc_mutex_trylock(mp) \
+       (*(mp) == 0 ? ((*(mp))++, ISC_R_SUCCESS) : ISC_R_LOCKBUSY)
+#define isc_mutex_destroy(mp) \
+       (*(mp) == 0 ? (*(mp) = -1, ISC_R_SUCCESS) : ISC_R_UNEXPECTED)
+#define isc_mutex_stats(fp)
+
+#endif /* ISC_MUTEX_H */
diff --git a/lib/isc/nothreads/include/isc/once.h b/lib/isc/nothreads/include/isc/once.h
new file mode 100644 (file)
index 0000000..ab705a4
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: once.h,v 1.6 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_ONCE_H
+#define ISC_ONCE_H 1
+
+#include <isc/result.h>
+
+typedef isc_boolean_t isc_once_t;
+
+#define ISC_ONCE_INIT ISC_FALSE
+
+#define isc_once_do(op, f) \
+       (!*(op) ? (f(), *(op) = ISC_TRUE, ISC_R_SUCCESS) : ISC_R_SUCCESS)
+
+#endif /* ISC_ONCE_H */
diff --git a/lib/isc/nothreads/include/isc/thread.h b/lib/isc/nothreads/include/isc/thread.h
new file mode 100644 (file)
index 0000000..313bc5f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: thread.h,v 1.6 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_THREAD_H
+#define ISC_THREAD_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_thread_setconcurrency(unsigned int level);
+
+#define isc_thread_self() ((unsigned long)0)
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_THREAD_H */
diff --git a/lib/isc/nothreads/mutex.c b/lib/isc/nothreads/mutex.c
new file mode 100644 (file)
index 0000000..50ba0f4
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2004, 2006, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: mutex.c,v 1.10 2007/06/19 23:47:18 tbox Exp $ */
+
+#include <config.h>
+
+#include <isc/util.h>
+
+EMPTY_TRANSLATION_UNIT
+
diff --git a/lib/isc/nothreads/thread.c b/lib/isc/nothreads/thread.c
new file mode 100644 (file)
index 0000000..9075e25
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: thread.c,v 1.5 2007/06/19 23:47:18 tbox Exp $ */
+
+#include <config.h>
+
+#include <isc/thread.h>
+#include <isc/util.h>
+
+void
+isc_thread_setconcurrency(unsigned int level) {
+       UNUSED(level);
+}
diff --git a/lib/isc/ondestroy.c b/lib/isc/ondestroy.c
new file mode 100644 (file)
index 0000000..32a75e1
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ondestroy.c,v 1.16 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/event.h>
+#include <isc/magic.h>
+#include <isc/ondestroy.h>
+#include <isc/task.h>
+#include <isc/util.h>
+
+#define ONDESTROY_MAGIC                ISC_MAGIC('D', 'e', 'S', 't')
+#define VALID_ONDESTROY(s)     ISC_MAGIC_VALID(s, ONDESTROY_MAGIC)
+
+void
+isc_ondestroy_init(isc_ondestroy_t *ondest) {
+       ondest->magic = ONDESTROY_MAGIC;
+       ISC_LIST_INIT(ondest->events);
+}
+
+isc_result_t
+isc_ondestroy_register(isc_ondestroy_t *ondest, isc_task_t *task,
+                      isc_event_t **eventp)
+{
+       isc_event_t *theevent;
+       isc_task_t *thetask = NULL;
+
+       REQUIRE(VALID_ONDESTROY(ondest));
+       REQUIRE(task != NULL);
+       REQUIRE(eventp != NULL);
+
+       theevent = *eventp;
+
+       REQUIRE(theevent != NULL);
+
+       isc_task_attach(task, &thetask);
+
+       theevent->ev_sender = thetask;
+
+       ISC_LIST_APPEND(ondest->events, theevent, ev_link);
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_ondestroy_notify(isc_ondestroy_t *ondest, void *sender) {
+       isc_event_t *eventp;
+       isc_task_t *task;
+
+       REQUIRE(VALID_ONDESTROY(ondest));
+
+       eventp = ISC_LIST_HEAD(ondest->events);
+       while (eventp != NULL) {
+               ISC_LIST_UNLINK(ondest->events, eventp, ev_link);
+
+               task = eventp->ev_sender;
+               eventp->ev_sender = sender;
+
+               isc_task_sendanddetach(&task, &eventp);
+
+               eventp = ISC_LIST_HEAD(ondest->events);
+       }
+}
+
+
diff --git a/lib/isc/parseint.c b/lib/isc/parseint.c
new file mode 100644 (file)
index 0000000..266d44c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: parseint.c,v 1.8 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <isc/parseint.h>
+#include <isc/result.h>
+#include <isc/stdlib.h>
+
+isc_result_t
+isc_parse_uint32(isc_uint32_t *uip, const char *string, int base) {
+       unsigned long n;
+       char *e;
+       if (! isalnum((unsigned char)(string[0])))
+               return (ISC_R_BADNUMBER);
+       errno = 0;
+       n = strtoul(string, &e, base);
+       if (*e != '\0')
+               return (ISC_R_BADNUMBER);
+       if (n == ULONG_MAX && errno == ERANGE)
+               return (ISC_R_RANGE);
+       *uip = n;
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_parse_uint16(isc_uint16_t *uip, const char *string, int base) {
+       isc_uint32_t val;
+       isc_result_t result;
+       result = isc_parse_uint32(&val, string, base);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       if (val > 0xFFFF)
+               return (ISC_R_RANGE);
+       *uip = (isc_uint16_t) val;
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_parse_uint8(isc_uint8_t *uip, const char *string, int base) {
+       isc_uint32_t val;
+       isc_result_t result;
+       result = isc_parse_uint32(&val, string, base);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       if (val > 0xFF)
+               return (ISC_R_RANGE);
+       *uip = (isc_uint8_t) val;
+       return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/portset.c b/lib/isc/portset.c
new file mode 100644 (file)
index 0000000..471ca8e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: portset.c,v 1.4 2008/06/24 23:24:35 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/portset.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#define ISC_PORTSET_BUFSIZE (65536 / (sizeof(isc_uint32_t) * 8))
+
+/*%
+ * Internal representation of portset.  It's an array of 32-bit integers, each
+ * bit corresponding to a single port in the ascending order.  For example,
+ * the second most significant bit of buf[0] corresponds to port 1.
+ */
+struct isc_portset {
+       unsigned int nports;    /*%< number of ports in the set */
+       isc_uint32_t buf[ISC_PORTSET_BUFSIZE];
+};
+
+static inline isc_boolean_t
+portset_isset(isc_portset_t *portset, in_port_t port) {
+       return (ISC_TF((portset->buf[port >> 5] & (1 << (port & 31))) != 0));
+}
+
+static inline void
+portset_add(isc_portset_t *portset, in_port_t port) {
+       if (!portset_isset(portset, port)) {
+               portset->nports++;
+               portset->buf[port >> 5] |= (1 << (port & 31));
+       }
+}
+
+static inline void
+portset_remove(isc_portset_t *portset, in_port_t port) {
+       if (portset_isset(portset, port)) {
+               portset->nports--;
+               portset->buf[port >> 5] &= ~(1 << (port & 31));
+       }
+}
+
+isc_result_t
+isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp) {
+       isc_portset_t *portset;
+
+       REQUIRE(portsetp != NULL && *portsetp == NULL);
+
+       portset = isc_mem_get(mctx, sizeof(*portset));
+       if (portset == NULL)
+               return (ISC_R_NOMEMORY);
+
+       /* Make the set 'empty' by default */
+       memset(portset, 0, sizeof(*portset));
+       *portsetp = portset;
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp) {
+       isc_portset_t *portset;
+
+       REQUIRE(portsetp != NULL);
+       portset = *portsetp;
+
+       isc_mem_put(mctx, portset, sizeof(*portset));
+}
+
+isc_boolean_t
+isc_portset_isset(isc_portset_t *portset, in_port_t port) {
+       REQUIRE(portset != NULL);
+
+       return (portset_isset(portset, port));
+}
+
+unsigned int
+isc_portset_nports(isc_portset_t *portset) {
+       REQUIRE(portset != NULL);
+
+       return (portset->nports);
+}
+
+void
+isc_portset_add(isc_portset_t *portset, in_port_t port) {
+       REQUIRE(portset != NULL);
+
+       portset_add(portset, port);
+}
+
+void
+isc_portset_remove(isc_portset_t *portset, in_port_t port) {
+       portset_remove(portset, port);
+}
+
+void
+isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo,
+                    in_port_t port_hi)
+{
+       in_port_t p;
+
+       REQUIRE(portset != NULL);
+       REQUIRE(port_lo <= port_hi);
+
+       p = port_lo;
+       do {
+               portset_add(portset, p);
+       } while (p++ < port_hi);
+}
+
+void
+isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo,
+                       in_port_t port_hi)
+{
+       in_port_t p;
+
+       REQUIRE(portset != NULL);
+       REQUIRE(port_lo <= port_hi);
+
+       p = port_lo;
+       do {
+               portset_remove(portset, p);
+       } while (p++ < port_hi);
+}
diff --git a/lib/isc/powerpc/include/isc/atomic.h b/lib/isc/powerpc/include/isc/atomic.h
new file mode 100644 (file)
index 0000000..765cb6d
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.6 2007/06/18 23:47:47 tbox Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+/*!\file
+ * static inline isc_int32_t
+ * isc_atomic_xadd(isc_int32_t *p, isc_int32_t val);
+ *
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ *
+ * static inline void
+ * isc_atomic_store(void *p, isc_int32_t val);
+ *
+ * This routine atomically stores the value 'val' in 'p'.
+ *
+ * static inline isc_int32_t
+ * isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val);
+ *
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'.  The original value is returned in any
+ * case.
+ */
+
+#if defined(_AIX)
+
+#include <sys/atomic_op.h>
+
+#define isc_atomic_xadd(p, v) fetch_and_add(p, v)
+#define isc_atomic_store(p, v) _clear_lock(p, v)
+
+#ifdef __GNUC__
+static inline int
+#else
+static int
+#endif
+isc_atomic_cmpxchg(atomic_p p, int old, int new) {
+        int orig = old;
+
+#ifdef __GNUC__
+        asm("ics");
+#else
+         __isync();
+#endif
+        if (compare_and_swap(p, &orig, new))
+               return (old);
+        return (orig);
+}
+
+#elif defined(ISC_PLATFORM_USEGCCASM) || defined(ISC_PLATFORM_USEMACASM)
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+       isc_int32_t orig;
+
+       __asm__ volatile (
+#ifdef ISC_PLATFORM_USEMACASM
+               "1:"
+               "lwarx r6, 0, %1\n"
+               "mr %0, r6\n"
+               "add r6, r6, %2\n"
+               "stwcx. r6, 0, %1\n"
+               "bne- 1b"
+#else
+               "1:"
+               "lwarx 6, 0, %1\n"
+               "mr %0, 6\n"
+               "add 6, 6, %2\n"
+               "stwcx. 6, 0, %1\n"
+               "bne- 1b"
+#endif
+               : "=&r"(orig)
+               : "r"(p), "r"(val)
+               : "r6", "memory"
+               );
+
+       return (orig);
+}
+
+static inline void
+isc_atomic_store(void *p, isc_int32_t val) {
+       __asm__ volatile (
+#ifdef ISC_PLATFORM_USEMACASM
+               "1:"
+               "lwarx r6, 0, %0\n"
+               "lwz r6, %1\n"
+               "stwcx. r6, 0, %0\n"
+               "bne- 1b"
+#else
+               "1:"
+               "lwarx 6, 0, %0\n"
+               "lwz 6, %1\n"
+               "stwcx. 6, 0, %0\n"
+               "bne- 1b"
+#endif
+               :
+               : "r"(p), "m"(val)
+               : "r6", "memory"
+               );
+}
+
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+       isc_int32_t orig;
+
+       __asm__ volatile (
+#ifdef ISC_PLATFORM_USEMACASM
+               "1:"
+               "lwarx r6, 0, %1\n"
+               "mr %0,r6\n"
+               "cmpw r6, %2\n"
+               "bne 2f\n"
+               "mr r6, %3\n"
+               "stwcx. r6, 0, %1\n"
+               "bne- 1b\n"
+               "2:"
+#else
+               "1:"
+               "lwarx 6, 0, %1\n"
+               "mr %0,6\n"
+               "cmpw 6, %2\n"
+               "bne 2f\n"
+               "mr 6, %3\n"
+               "stwcx. 6, 0, %1\n"
+               "bne- 1b\n"
+               "2:"
+#endif
+               : "=&r" (orig)
+               : "r"(p), "r"(cmpval), "r"(val)
+               : "r6", "memory"
+               );
+
+       return (orig);
+}
+
+#else
+
+#error "unsupported compiler.  disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/print.c b/lib/isc/print.c
new file mode 100644 (file)
index 0000000..b892e3a
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: print.c,v 1.35 2008/02/18 23:46:59 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdio.h>             /* for sprintf() */
+#include <string.h>            /* for strlen() */
+
+#define        ISC__PRINT_SOURCE       /* Used to get the isc_print_* prototypes. */
+
+#include <isc/assertions.h>
+#include <isc/int.h>
+#include <isc/msgs.h>
+#include <isc/print.h>
+#include <isc/stdlib.h>
+#include <isc/util.h>
+
+int
+isc_print_sprintf(char *str, const char *format, ...) {
+       va_list ap;
+
+       va_start(ap, format);
+       vsprintf(str, format, ap);
+       va_end(ap);
+       return (strlen(str));
+}
+
+/*!
+ * Return length of string that would have been written if not truncated.
+ */
+
+int
+isc_print_snprintf(char *str, size_t size, const char *format, ...) {
+       va_list ap;
+       int ret;
+
+       va_start(ap, format);
+       ret = vsnprintf(str, size, format, ap);
+       va_end(ap);
+       return (ret);
+
+}
+
+/*!
+ * Return length of string that would have been written if not truncated.
+ */
+
+int
+isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
+       int h;
+       int l;
+       int q;
+       int alt;
+       int zero;
+       int left;
+       int plus;
+       int space;
+       int neg;
+       isc_int64_t tmpi;
+       isc_uint64_t tmpui;
+       unsigned long width;
+       unsigned long precision;
+       unsigned int length;
+       char buf[1024];
+       char c;
+       void *v;
+       char *save = str;
+       const char *cp;
+       const char *head;
+       int count = 0;
+       int pad;
+       int zeropad;
+       int dot;
+       double dbl;
+#ifdef HAVE_LONG_DOUBLE
+       long double ldbl;
+#endif
+       char fmt[32];
+
+       INSIST(str != NULL);
+       INSIST(format != NULL);
+
+       while (*format != '\0') {
+               if (*format != '%') {
+                       if (size > 1) {
+                               *str++ = *format;
+                               size--;
+                       }
+                       count++;
+                       format++;
+                       continue;
+               }
+               format++;
+
+               /*
+                * Reset flags.
+                */
+               dot = neg = space = plus = left = zero = alt = h = l = q = 0;
+               width = precision = 0;
+               head = "";
+               length = pad = zeropad = 0;
+
+               do {
+                       if (*format == '#') {
+                               alt = 1;
+                               format++;
+                       } else if (*format == '-') {
+                               left = 1;
+                               zero = 0;
+                               format++;
+                       } else if (*format == ' ') {
+                               if (!plus)
+                                       space = 1;
+                               format++;
+                       } else if (*format == '+') {
+                               plus = 1;
+                               space = 0;
+                               format++;
+                       } else if (*format == '0') {
+                               if (!left)
+                                       zero = 1;
+                               format++;
+                       } else
+                               break;
+               } while (1);
+
+               /*
+                * Width.
+                */
+               if (*format == '*') {
+                       width = va_arg(ap, int);
+                       format++;
+               } else if (isdigit((unsigned char)*format)) {
+                       char *e;
+                       width = strtoul(format, &e, 10);
+                       format = e;
+               }
+
+               /*
+                * Precision.
+                */
+               if (*format == '.') {
+                       format++;
+                       dot = 1;
+                       if (*format == '*') {
+                               precision = va_arg(ap, int);
+                               format++;
+                       } else if (isdigit((unsigned char)*format)) {
+                               char *e;
+                               precision = strtoul(format, &e, 10);
+                               format = e;
+                       }
+               }
+
+               switch (*format) {
+               case '\0':
+                       continue;
+               case '%':
+                       if (size > 1) {
+                               *str++ = *format;
+                               size--;
+                       }
+                       count++;
+                       break;
+               case 'q':
+                       q = 1;
+                       format++;
+                       goto doint;
+               case 'h':
+                       h = 1;
+                       format++;
+                       goto doint;
+               case 'l':
+                       l = 1;
+                       format++;
+                       if (*format == 'l') {
+                               q = 1;
+                               format++;
+                       }
+                       goto doint;
+               case 'n':
+               case 'i':
+               case 'd':
+               case 'o':
+               case 'u':
+               case 'x':
+               case 'X':
+               doint:
+                       if (precision != 0)
+                               zero = 0;
+                       switch (*format) {
+                       case 'n':
+                               if (h) {
+                                       short int *p;
+                                       p = va_arg(ap, short *);
+                                       REQUIRE(p != NULL);
+                                       *p = str - save;
+                               } else if (l) {
+                                       long int *p;
+                                       p = va_arg(ap, long *);
+                                       REQUIRE(p != NULL);
+                                       *p = str - save;
+                               } else {
+                                       int *p;
+                                       p = va_arg(ap, int *);
+                                       REQUIRE(p != NULL);
+                                       *p = str - save;
+                               }
+                               break;
+                       case 'i':
+                       case 'd':
+                               if (q)
+                                       tmpi = va_arg(ap, isc_int64_t);
+                               else if (l)
+                                       tmpi = va_arg(ap, long int);
+                               else
+                                       tmpi = va_arg(ap, int);
+                               if (tmpi < 0) {
+                                       head = "-";
+                                       tmpui = -tmpi;
+                               } else {
+                                       if (plus)
+                                               head = "+";
+                                       else if (space)
+                                               head = " ";
+                                       else
+                                               head = "";
+                                       tmpui = tmpi;
+                               }
+                               if (tmpui <= 0xffffffffU)
+                                       sprintf(buf, "%lu",
+                                               (unsigned long)tmpui);
+                               else {
+                                       unsigned long mid;
+                                       unsigned long lo;
+                                       unsigned long hi;
+                                       lo = tmpui % 1000000000;
+                                       tmpui /= 1000000000;
+                                       mid = tmpui % 1000000000;
+                                       hi = tmpui / 1000000000;
+                                       if (hi != 0)
+                                               sprintf(buf, "%lu", hi);
+                                       else
+                                               buf[0] = '\n';
+                                       sprintf(buf + strlen(buf), "%lu", mid);
+                                       sprintf(buf + strlen(buf), "%lu", lo);
+                               }
+                               goto printint;
+                       case 'o':
+                               if (q)
+                                       tmpui = va_arg(ap, isc_uint64_t);
+                               else if (l)
+                                       tmpui = va_arg(ap, long int);
+                               else
+                                       tmpui = va_arg(ap, int);
+                               if (tmpui <= 0xffffffffU)
+                                       sprintf(buf, alt ?  "%#lo" : "%lo",
+                                               (unsigned long)tmpui);
+                               else {
+                                       unsigned long mid;
+                                       unsigned long lo;
+                                       unsigned long hi;
+                                       lo = tmpui % 010000000000;
+                                       tmpui /= 010000000000;
+                                       mid = tmpui % 010000000000;
+                                       hi = tmpui / 010000000000;
+                                       if (hi != 0) {
+                                               sprintf(buf,
+                                                       alt ?  "%#lo" : "%lo",
+                                                       hi);
+                                               sprintf(buf + strlen(buf),
+                                                       "%lo", mid);
+                                       } else
+                                               sprintf(buf,
+                                                       alt ?  "%#lo" : "%lo",
+                                                       mid);
+                                       sprintf(buf + strlen(buf), "%lo", lo);
+                               }
+                               goto printint;
+                       case 'u':
+                               if (q)
+                                       tmpui = va_arg(ap, isc_uint64_t);
+                               else if (l)
+                                       tmpui = va_arg(ap, unsigned long int);
+                               else
+                                       tmpui = va_arg(ap, unsigned int);
+                               if (tmpui <= 0xffffffffU)
+                                       sprintf(buf, "%lu",
+                                               (unsigned long)tmpui);
+                               else {
+                                       unsigned long mid;
+                                       unsigned long lo;
+                                       unsigned long hi;
+                                       lo = tmpui % 1000000000;
+                                       tmpui /= 1000000000;
+                                       mid = tmpui % 1000000000;
+                                       hi = tmpui / 1000000000;
+                                       if (hi != 0)
+                                               sprintf(buf, "%lu", hi);
+                                       else
+                                               buf[0] = '\n';
+                                       sprintf(buf + strlen(buf), "%lu", mid);
+                                       sprintf(buf + strlen(buf), "%lu", lo);
+                               }
+                               goto printint;
+                       case 'x':
+                               if (q)
+                                       tmpui = va_arg(ap, isc_uint64_t);
+                               else if (l)
+                                       tmpui = va_arg(ap, unsigned long int);
+                               else
+                                       tmpui = va_arg(ap, unsigned int);
+                               if (alt) {
+                                       head = "0x";
+                                       if (precision > 2)
+                                               precision -= 2;
+                               }
+                               if (tmpui <= 0xffffffffU)
+                                       sprintf(buf, "%lx",
+                                               (unsigned long)tmpui);
+                               else {
+                                       unsigned long hi = tmpui>>32;
+                                       unsigned long lo = tmpui & 0xffffffff;
+                                       sprintf(buf, "%lx", hi);
+                                       sprintf(buf + strlen(buf), "%lx", lo);
+                               }
+                               goto printint;
+                       case 'X':
+                               if (q)
+                                       tmpui = va_arg(ap, isc_uint64_t);
+                               else if (l)
+                                       tmpui = va_arg(ap, unsigned long int);
+                               else
+                                       tmpui = va_arg(ap, unsigned int);
+                               if (alt) {
+                                       head = "0X";
+                                       if (precision > 2)
+                                               precision -= 2;
+                               }
+                               if (tmpui <= 0xffffffffU)
+                                       sprintf(buf, "%lX",
+                                               (unsigned long)tmpui);
+                               else  {
+                                       unsigned long hi = tmpui>>32;
+                                       unsigned long lo = tmpui & 0xffffffff;
+                                       sprintf(buf, "%lX", hi);
+                                       sprintf(buf + strlen(buf), "%lX", lo);
+                               }
+                               goto printint;
+                       printint:
+                               if (precision != 0 || width != 0) {
+                                       length = strlen(buf);
+                                       if (length < precision)
+                                               zeropad = precision - length;
+                                       else if (length < width && zero)
+                                               zeropad = width - length;
+                                       if (width != 0) {
+                                               pad = width - length -
+                                                     zeropad - strlen(head);
+                                               if (pad < 0)
+                                                       pad = 0;
+                                       }
+                               }
+                               count += strlen(head) + strlen(buf) + pad +
+                                        zeropad;
+                               if (!left) {
+                                       while (pad > 0 && size > 1) {
+                                               *str++ = ' ';
+                                               size--;
+                                               pad--;
+                                       }
+                               }
+                               cp = head;
+                               while (*cp != '\0' && size > 1) {
+                                       *str++ = *cp++;
+                                       size--;
+                               }
+                               while (zeropad > 0 && size > 1) {
+                                       *str++ = '0';
+                                       size--;
+                                       zeropad--;
+                               }
+                               cp = buf;
+                               while (*cp != '\0' && size > 1) {
+                                       *str++ = *cp++;
+                                       size--;
+                               }
+                               while (pad > 0 && size > 1) {
+                                       *str++ = ' ';
+                                       size--;
+                                       pad--;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               case 's':
+                       cp = va_arg(ap, char *);
+                       REQUIRE(cp != NULL);
+
+                       if (precision != 0) {
+                               /*
+                                * cp need not be NULL terminated.
+                                */
+                               const char *tp;
+                               unsigned long n;
+
+                               n = precision;
+                               tp = cp;
+                               while (n != 0 && *tp != '\0')
+                                       n--, tp++;
+                               length = precision - n;
+                       } else {
+                               length = strlen(cp);
+                       }
+                       if (width != 0) {
+                               pad = width - length;
+                               if (pad < 0)
+                                       pad = 0;
+                       }
+                       count += pad + length;
+                       if (!left)
+                               while (pad > 0 && size > 1) {
+                                       *str++ = ' ';
+                                       size--;
+                                       pad--;
+                               }
+                       if (precision != 0)
+                               while (precision > 0 && *cp != '\0' &&
+                                      size > 1) {
+                                       *str++ = *cp++;
+                                       size--;
+                                       precision--;
+                               }
+                       else
+                               while (*cp != '\0' && size > 1) {
+                                       *str++ = *cp++;
+                                       size--;
+                               }
+                       while (pad > 0 && size > 1) {
+                               *str++ = ' ';
+                               size--;
+                               pad--;
+                       }
+                       break;
+               case 'c':
+                       c = va_arg(ap, int);
+                       if (width > 0) {
+                               count += width;
+                               width--;
+                               if (left) {
+                                       *str++ = c;
+                                       size--;
+                               }
+                               while (width-- > 0 && size > 1) {
+                                       *str++ = ' ';
+                                       size--;
+                               }
+                               if (!left && size > 1) {
+                                       *str++ = c;
+                                       size--;
+                               }
+                       } else {
+                               count++;
+                               if (size > 1) {
+                                       *str++ = c;
+                                       size--;
+                               }
+                       }
+                       break;
+               case 'p':
+                       v = va_arg(ap, void *);
+                       sprintf(buf, "%p", v);
+                       length = strlen(buf);
+                       if (precision > length)
+                               zeropad = precision - length;
+                       if (width > 0) {
+                               pad = width - length - zeropad;
+                               if (pad < 0)
+                                       pad = 0;
+                       }
+                       count += length + pad + zeropad;
+                       if (!left)
+                               while (pad > 0 && size > 1) {
+                                       *str++ = ' ';
+                                       size--;
+                                       pad--;
+                               }
+                       cp = buf;
+                       if (zeropad > 0 && buf[0] == '0' &&
+                           (buf[1] == 'x' || buf[1] == 'X')) {
+                               if (size > 1) {
+                                       *str++ = *cp++;
+                                       size--;
+                               }
+                               if (size > 1) {
+                                       *str++ = *cp++;
+                                       size--;
+                               }
+                               while (zeropad > 0 && size > 1) {
+                                       *str++ = '0';
+                                       size--;
+                                       zeropad--;
+                               }
+                       }
+                       while (*cp != '\0' && size > 1) {
+                               *str++ = *cp++;
+                               size--;
+                       }
+                       while (pad > 0 && size > 1) {
+                               *str++ = ' ';
+                               size--;
+                               pad--;
+                       }
+                       break;
+               case 'D':       /*deprecated*/
+                       INSIST("use %ld instead of %D" == NULL);
+               case 'O':       /*deprecated*/
+                       INSIST("use %lo instead of %O" == NULL);
+               case 'U':       /*deprecated*/
+                       INSIST("use %lu instead of %U" == NULL);
+
+               case 'L':
+#ifdef HAVE_LONG_DOUBLE
+                       l = 1;
+#else
+                       INSIST("long doubles are not supported" == NULL);
+#endif
+                       /*FALLTHROUGH*/
+               case 'e':
+               case 'E':
+               case 'f':
+               case 'g':
+               case 'G':
+                       if (!dot)
+                               precision = 6;
+                       /*
+                        * IEEE floating point.
+                        * MIN 2.2250738585072014E-308
+                        * MAX 1.7976931348623157E+308
+                        * VAX floating point has a smaller range than IEEE.
+                        *
+                        * precisions > 324 don't make much sense.
+                        * if we cap the precision at 512 we will not
+                        * overflow buf.
+                        */
+                       if (precision > 512)
+                               precision = 512;
+                       sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
+                               plus ? "+" : space ? " " : "",
+                               precision, l ? "L" : "", *format);
+                       switch (*format) {
+                       case 'e':
+                       case 'E':
+                       case 'f':
+                       case 'g':
+                       case 'G':
+#ifdef HAVE_LONG_DOUBLE
+                               if (l) {
+                                       ldbl = va_arg(ap, long double);
+                                       sprintf(buf, fmt, ldbl);
+                               } else
+#endif
+                               {
+                                       dbl = va_arg(ap, double);
+                                       sprintf(buf, fmt, dbl);
+                               }
+                               length = strlen(buf);
+                               if (width > 0) {
+                                       pad = width - length;
+                                       if (pad < 0)
+                                               pad = 0;
+                               }
+                               count += length + pad;
+                               if (!left)
+                                       while (pad > 0 && size > 1) {
+                                               *str++ = ' ';
+                                               size--;
+                                               pad--;
+                                       }
+                               cp = buf;
+                               while (*cp != ' ' && size > 1) {
+                                       *str++ = *cp++;
+                                       size--;
+                               }
+                               while (pad > 0 && size > 1) {
+                                       *str++ = ' ';
+                                       size--;
+                                       pad--;
+                               }
+                               break;
+                       default:
+                               continue;
+                       }
+                       break;
+               default:
+                       continue;
+               }
+               format++;
+       }
+       if (size > 0)
+               *str = '\0';
+       return (count);
+}
diff --git a/lib/isc/pthreads/condition.c b/lib/isc/pthreads/condition.c
new file mode 100644 (file)
index 0000000..50281a2
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: condition.c,v 1.36 2007/06/19 23:47:18 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+
+#include <isc/condition.h>
+#include <isc/msgs.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *c, isc_mutex_t *m, isc_time_t *t) {
+       int presult;
+       isc_result_t result;
+       struct timespec ts;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(c != NULL && m != NULL && t != NULL);
+
+       /*
+        * POSIX defines a timespec's tv_sec as time_t.
+        */
+       result = isc_time_secondsastimet(t, &ts.tv_sec);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       /*!
+        * POSIX defines a timespec's tv_nsec as long.  isc_time_nanoseconds
+        * ensures its return value is < 1 billion, which will fit in a long.
+        */
+       ts.tv_nsec = (long)isc_time_nanoseconds(t);
+
+       do {
+#if ISC_MUTEX_PROFILE
+               presult = pthread_cond_timedwait(c, &m->mutex, &ts);
+#else
+               presult = pthread_cond_timedwait(c, m, &ts);
+#endif
+               if (presult == 0)
+                       return (ISC_R_SUCCESS);
+               if (presult == ETIMEDOUT)
+                       return (ISC_R_TIMEDOUT);
+       } while (presult == EINTR);
+
+       isc__strerror(presult, strbuf, sizeof(strbuf));
+       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                        "pthread_cond_timedwait() %s %s",
+                        isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                       ISC_MSG_RETURNED, "returned"),
+                        strbuf);
+       return (ISC_R_UNEXPECTED);
+}
diff --git a/lib/isc/pthreads/include/isc/condition.h b/lib/isc/pthreads/include/isc/condition.h
new file mode 100644 (file)
index 0000000..04a6118
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: condition.h,v 1.26 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_CONDITION_H
+#define ISC_CONDITION_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/result.h>
+#include <isc/types.h>
+
+typedef pthread_cond_t isc_condition_t;
+
+#define isc_condition_init(cp) \
+       ((pthread_cond_init((cp), NULL) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#if ISC_MUTEX_PROFILE
+#define isc_condition_wait(cp, mp) \
+       ((pthread_cond_wait((cp), &((mp)->mutex)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#else
+#define isc_condition_wait(cp, mp) \
+       ((pthread_cond_wait((cp), (mp)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#define isc_condition_signal(cp) \
+       ((pthread_cond_signal((cp)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_condition_broadcast(cp) \
+       ((pthread_cond_broadcast((cp)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_condition_destroy(cp) \
+       ((pthread_cond_destroy((cp)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_CONDITION_H */
diff --git a/lib/isc/pthreads/include/isc/mutex.h b/lib/isc/pthreads/include/isc/mutex.h
new file mode 100644 (file)
index 0000000..dd7d326
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: mutex.h,v 1.30 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_MUTEX_H
+#define ISC_MUTEX_H 1
+
+/*! \file */
+
+#include <pthread.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>                /* for ISC_R_ codes */
+
+ISC_LANG_BEGINDECLS
+
+/*!
+ * Supply mutex attributes that enable deadlock detection
+ * (helpful when debugging).  This is system dependent and
+ * currently only supported on NetBSD.
+ */
+#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
+extern pthread_mutexattr_t isc__mutex_attrs;
+#define ISC__MUTEX_ATTRS &isc__mutex_attrs
+#else
+#define ISC__MUTEX_ATTRS NULL
+#endif
+
+/* XXX We could do fancier error handling... */
+
+/*!
+ * Define ISC_MUTEX_PROFILE to turn on profiling of mutexes by line.  When
+ * enabled, isc_mutex_stats() can be used to print a table showing the
+ * number of times each type of mutex was locked and the amount of time
+ * waiting to obtain the lock.
+ */
+#ifndef ISC_MUTEX_PROFILE
+#define ISC_MUTEX_PROFILE 0
+#endif
+
+#if ISC_MUTEX_PROFILE
+typedef struct isc_mutexstats isc_mutexstats_t;
+
+typedef struct {
+       pthread_mutex_t         mutex;  /*%< The actual mutex. */
+       isc_mutexstats_t *      stats;  /*%< Mutex statistics. */
+} isc_mutex_t;
+#else
+typedef pthread_mutex_t        isc_mutex_t;
+#endif
+
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_init(mp) \
+       isc_mutex_init_profile((mp), __FILE__, __LINE__)
+#else
+#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
+#define isc_mutex_init(mp) \
+        isc_mutex_init_errcheck((mp))
+#else
+#define isc_mutex_init(mp) \
+       isc__mutex_init((mp), __FILE__, __LINE__)
+isc_result_t isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line);
+#endif
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_lock(mp) \
+       isc_mutex_lock_profile((mp), __FILE__, __LINE__)
+#else
+#define isc_mutex_lock(mp) \
+       ((pthread_mutex_lock((mp)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_unlock(mp) \
+       isc_mutex_unlock_profile((mp), __FILE__, __LINE__)
+#else
+#define isc_mutex_unlock(mp) \
+       ((pthread_mutex_unlock((mp)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_trylock(mp) \
+       ((pthread_mutex_trylock((&(mp)->mutex)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_LOCKBUSY)
+#else
+#define isc_mutex_trylock(mp) \
+       ((pthread_mutex_trylock((mp)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_LOCKBUSY)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_destroy(mp) \
+       ((pthread_mutex_destroy((&(mp)->mutex)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#else
+#define isc_mutex_destroy(mp) \
+       ((pthread_mutex_destroy((mp)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+#endif
+
+#if ISC_MUTEX_PROFILE
+#define isc_mutex_stats(fp) isc_mutex_statsprofile(fp);
+#else
+#define isc_mutex_stats(fp)
+#endif
+
+#if ISC_MUTEX_PROFILE
+
+isc_result_t
+isc_mutex_init_profile(isc_mutex_t *mp, const char * _file, int _line);
+isc_result_t
+isc_mutex_lock_profile(isc_mutex_t *mp, const char * _file, int _line);
+isc_result_t
+isc_mutex_unlock_profile(isc_mutex_t *mp, const char * _file, int _line);
+
+void
+isc_mutex_statsprofile(FILE *fp);
+
+isc_result_t
+isc_mutex_init_errcheck(isc_mutex_t *mp);
+
+#endif /* ISC_MUTEX_PROFILE */
+
+ISC_LANG_ENDDECLS
+#endif /* ISC_MUTEX_H */
diff --git a/lib/isc/pthreads/include/isc/once.h b/lib/isc/pthreads/include/isc/once.h
new file mode 100644 (file)
index 0000000..31d76fb
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: once.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_ONCE_H
+#define ISC_ONCE_H 1
+
+/*! \file */
+
+#include <pthread.h>
+
+#include <isc/platform.h>
+#include <isc/result.h>
+
+typedef pthread_once_t isc_once_t;
+
+#ifdef ISC_PLATFORM_BRACEPTHREADONCEINIT
+/*!
+ * This accomodates systems that define PTHRAD_ONCE_INIT improperly.
+ */
+#define ISC_ONCE_INIT { PTHREAD_ONCE_INIT }
+#else
+/*!
+ * This is the usual case.
+ */
+#define ISC_ONCE_INIT PTHREAD_ONCE_INIT
+#endif
+
+/* XXX We could do fancier error handling... */
+
+#define isc_once_do(op, f) \
+       ((pthread_once((op), (f)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#endif /* ISC_ONCE_H */
diff --git a/lib/isc/pthreads/include/isc/thread.h b/lib/isc/pthreads/include/isc/thread.h
new file mode 100644 (file)
index 0000000..7dcc952
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: thread.h,v 1.26 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef ISC_THREAD_H
+#define ISC_THREAD_H 1
+
+/*! \file */
+
+#include <pthread.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef pthread_t isc_thread_t;
+typedef void * isc_threadresult_t;
+typedef void * isc_threadarg_t;
+typedef isc_threadresult_t (*isc_threadfunc_t)(isc_threadarg_t);
+typedef pthread_key_t isc_thread_key_t;
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *);
+
+void
+isc_thread_setconcurrency(unsigned int level);
+
+/* XXX We could do fancier error handling... */
+
+#define isc_thread_join(t, rp) \
+       ((pthread_join((t), (rp)) == 0) ? \
+        ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_thread_self \
+       (unsigned long)pthread_self
+
+#define isc_thread_key_create pthread_key_create
+#define isc_thread_key_getspecific pthread_getspecific
+#define isc_thread_key_setspecific pthread_setspecific
+#define isc_thread_key_delete pthread_key_delete
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_THREAD_H */
diff --git a/lib/isc/pthreads/mutex.c b/lib/isc/pthreads/mutex.c
new file mode 100644 (file)
index 0000000..b57d9ee
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: mutex.c,v 1.16 2008/04/04 23:47:01 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include <isc/mutex.h>
+#include <isc/util.h>
+#include <isc/strerror.h>
+
+#if ISC_MUTEX_PROFILE
+
+/*@{*/
+/*% Operations on timevals; adapted from FreeBSD's sys/time.h */
+#define timevalclear(tvp)      ((tvp)->tv_sec = (tvp)->tv_usec = 0)
+#define timevaladd(vvp, uvp)                                            \
+       do {                                                            \
+               (vvp)->tv_sec += (uvp)->tv_sec;                         \
+               (vvp)->tv_usec += (uvp)->tv_usec;                       \
+               if ((vvp)->tv_usec >= 1000000) {                        \
+                       (vvp)->tv_sec++;                                \
+                       (vvp)->tv_usec -= 1000000;                      \
+               }                                                       \
+       } while (0)
+#define timevalsub(vvp, uvp)                                            \
+       do {                                                            \
+               (vvp)->tv_sec -= (uvp)->tv_sec;                         \
+               (vvp)->tv_usec -= (uvp)->tv_usec;                       \
+               if ((vvp)->tv_usec < 0) {                               \
+                       (vvp)->tv_sec--;                                \
+                       (vvp)->tv_usec += 1000000;                      \
+               }                                                       \
+       } while (0)
+
+/*@}*/
+
+#define ISC_MUTEX_MAX_LOCKERS 32
+
+typedef struct {
+       const char *            file;
+       int                     line;
+       unsigned                count;
+       struct timeval          locked_total;
+       struct timeval          wait_total;
+} isc_mutexlocker_t;
+
+struct isc_mutexstats {
+       const char *            file;   /*%< File mutex was created in. */
+       int                     line;   /*%< Line mutex was created on. */
+       unsigned                count;
+       struct timeval          lock_t;
+       struct timeval          locked_total;
+       struct timeval          wait_total;
+       isc_mutexlocker_t *     cur_locker;
+       isc_mutexlocker_t       lockers[ISC_MUTEX_MAX_LOCKERS];
+};
+
+#ifndef ISC_MUTEX_PROFTABLESIZE
+#define ISC_MUTEX_PROFTABLESIZE (16 * 1024)
+#endif
+static isc_mutexstats_t stats[ISC_MUTEX_PROFTABLESIZE];
+static int stats_next = 0;
+static isc_boolean_t stats_init = ISC_FALSE;
+static pthread_mutex_t statslock = PTHREAD_MUTEX_INITIALIZER;
+
+
+isc_result_t
+isc_mutex_init_profile(isc_mutex_t *mp, const char *file, int line) {
+       int i, err;
+
+       err = pthread_mutex_init(&mp->mutex, NULL);
+       if (err == ENOMEM)
+               return (ISC_R_NOMEMORY);
+       if (err != 0)
+               return (ISC_R_UNEXPECTED);
+
+       RUNTIME_CHECK(pthread_mutex_lock(&statslock) == 0);
+
+       if (stats_init == ISC_FALSE)
+               stats_init = ISC_TRUE;
+
+       /*
+        * If all statistics entries have been used, give up and trigger an
+        * assertion failure.  There would be no other way to deal with this
+        * because we'd like to keep record of all locks for the purpose of
+        * debugging and the number of necessary locks is unpredictable.
+        * If this failure is triggered while debugging, named should be
+        * rebuilt with an increased ISC_MUTEX_PROFTABLESIZE.
+        */
+       RUNTIME_CHECK(stats_next < ISC_MUTEX_PROFTABLESIZE);
+       mp->stats = &stats[stats_next++];
+
+       RUNTIME_CHECK(pthread_mutex_unlock(&statslock) == 0);
+
+       mp->stats->file = file;
+       mp->stats->line = line;
+       mp->stats->count = 0;
+       timevalclear(&mp->stats->locked_total);
+       timevalclear(&mp->stats->wait_total);
+       for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
+               mp->stats->lockers[i].file = NULL;
+               mp->stats->lockers[i].line = 0;
+               mp->stats->lockers[i].count = 0;
+               timevalclear(&mp->stats->lockers[i].locked_total);
+               timevalclear(&mp->stats->lockers[i].wait_total);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_mutex_lock_profile(isc_mutex_t *mp, const char *file, int line) {
+       struct timeval prelock_t;
+       struct timeval postlock_t;
+       isc_mutexlocker_t *locker = NULL;
+       int i;
+
+       gettimeofday(&prelock_t, NULL);
+
+       if (pthread_mutex_lock(&mp->mutex) != 0)
+               return (ISC_R_UNEXPECTED);
+
+       gettimeofday(&postlock_t, NULL);
+       mp->stats->lock_t = postlock_t;
+
+       timevalsub(&postlock_t, &prelock_t);
+
+       mp->stats->count++;
+       timevaladd(&mp->stats->wait_total, &postlock_t);
+
+       for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) {
+               if (mp->stats->lockers[i].file == NULL) {
+                       locker = &mp->stats->lockers[i];
+                       locker->file = file;
+                       locker->line = line;
+                       break;
+               } else if (mp->stats->lockers[i].file == file &&
+                          mp->stats->lockers[i].line == line) {
+                       locker = &mp->stats->lockers[i];
+                       break;
+               }
+       }
+
+       if (locker != NULL) {
+               locker->count++;
+               timevaladd(&locker->wait_total, &postlock_t);
+       }
+
+       mp->stats->cur_locker = locker;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_mutex_unlock_profile(isc_mutex_t *mp, const char *file, int line) {
+       struct timeval unlock_t;
+
+       UNUSED(file);
+       UNUSED(line);
+
+       if (mp->stats->cur_locker != NULL) {
+               gettimeofday(&unlock_t, NULL);
+               timevalsub(&unlock_t, &mp->stats->lock_t);
+               timevaladd(&mp->stats->locked_total, &unlock_t);
+               timevaladd(&mp->stats->cur_locker->locked_total, &unlock_t);
+               mp->stats->cur_locker = NULL;
+       }
+
+       return ((pthread_mutex_unlock((&mp->mutex)) == 0) ? \
+               ISC_R_SUCCESS : ISC_R_UNEXPECTED);
+}
+
+
+void
+isc_mutex_statsprofile(FILE *fp) {
+       isc_mutexlocker_t *locker;
+       int i, j;
+
+       fprintf(fp, "Mutex stats (in us)\n");
+       for (i = 0; i < stats_next; i++) {
+               fprintf(fp, "%-12s %4d: %10u  %lu.%06lu %lu.%06lu\n",
+                       stats[i].file, stats[i].line, stats[i].count,
+                       stats[i].locked_total.tv_sec,
+                       stats[i].locked_total.tv_usec,
+                       stats[i].wait_total.tv_sec,
+                       stats[i].wait_total.tv_usec
+                       );
+               for (j = 0; j < ISC_MUTEX_MAX_LOCKERS; j++) {
+                       locker = &stats[i].lockers[j];
+                       if (locker->file == NULL)
+                               continue;
+                       fprintf(fp, " %-11s %4d: %10u  %lu.%06lu %lu.%06lu\n",
+                               locker->file, locker->line, locker->count,
+                               locker->locked_total.tv_sec,
+                               locker->locked_total.tv_usec,
+                               locker->wait_total.tv_sec,
+                               locker->wait_total.tv_usec
+                               );
+               }
+       }
+}
+
+#endif /* ISC_MUTEX_PROFILE */
+
+#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)
+isc_result_t
+isc_mutex_init_errcheck(isc_mutex_t *mp)
+{
+       pthread_mutexattr_t attr;
+       int err;
+
+       if (pthread_mutexattr_init(&attr) != 0)
+               return (ISC_R_UNEXPECTED);
+
+       if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
+               return (ISC_R_UNEXPECTED);
+
+       err = pthread_mutex_init(mp, &attr) != 0)
+       if (err == ENOMEM)
+               return (ISC_R_NOMEMORY);
+       return ((err == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED);
+}
+#endif
+
+#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK)
+pthread_mutexattr_t isc__mutex_attrs = {
+       PTHREAD_MUTEX_ERRORCHECK,       /* m_type */
+       0                               /* m_flags, which appears to be unused. */
+};
+#endif
+
+#if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && !ISC_MUTEX_PROFILE
+isc_result_t
+isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) {
+       char strbuf[ISC_STRERRORSIZE];
+       isc_result_t result = ISC_R_SUCCESS;
+       int err;
+
+       err = pthread_mutex_init(mp, ISC__MUTEX_ATTRS);
+       if (err == ENOMEM)
+               return (ISC_R_NOMEMORY);
+       if (err != 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(file, line, "isc_mutex_init() failed: %s",
+                                strbuf);
+               result = ISC_R_UNEXPECTED;
+       }
+       return (result);
+}
+#endif
diff --git a/lib/isc/pthreads/thread.c b/lib/isc/pthreads/thread.c
new file mode 100644 (file)
index 0000000..4b5b491
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: thread.c,v 1.17 2007/06/19 23:47:18 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#ifndef THREAD_MINSTACKSIZE
+#define THREAD_MINSTACKSIZE            (64U * 1024)
+#endif
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t func, isc_threadarg_t arg,
+                 isc_thread_t *thread)
+{
+       pthread_attr_t attr;
+       size_t stacksize;
+       int ret;
+
+       pthread_attr_init(&attr);
+
+#if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \
+    defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE)
+       ret = pthread_attr_getstacksize(&attr, &stacksize);
+       if (ret != 0)
+               return (ISC_R_UNEXPECTED);
+
+       if (stacksize < THREAD_MINSTACKSIZE) {
+               ret = pthread_attr_setstacksize(&attr, THREAD_MINSTACKSIZE);
+               if (ret != 0)
+                       return (ISC_R_UNEXPECTED);
+       }
+#endif
+
+#if defined(PTHREAD_SCOPE_SYSTEM) && defined(NEED_PTHREAD_SCOPE_SYSTEM)
+       ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+       if (ret != 0)
+               return (ISC_R_UNEXPECTED);
+#endif
+
+       ret = pthread_create(thread, &attr, func, arg);
+       if (ret != 0)
+               return (ISC_R_UNEXPECTED);
+
+       pthread_attr_destroy(&attr);
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_thread_setconcurrency(unsigned int level) {
+#if defined(CALL_PTHREAD_SETCONCURRENCY)
+       (void)pthread_setconcurrency(level);
+#else
+       UNUSED(level);
+#endif
+}
diff --git a/lib/isc/quota.c b/lib/isc/quota.c
new file mode 100644 (file)
index 0000000..5e5c50c
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: quota.c,v 1.18 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/quota.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_quota_init(isc_quota_t *quota, int max) {
+       quota->max = max;
+       quota->used = 0;
+       quota->soft = 0;
+       return (isc_mutex_init(&quota->lock));
+}
+
+void
+isc_quota_destroy(isc_quota_t *quota) {
+       INSIST(quota->used == 0);
+       quota->max = 0;
+       quota->used = 0;
+       quota->soft = 0;
+       DESTROYLOCK(&quota->lock);
+}
+
+void
+isc_quota_soft(isc_quota_t *quota, int soft) {
+       LOCK(&quota->lock);
+       quota->soft = soft;
+       UNLOCK(&quota->lock);
+}
+
+void
+isc_quota_max(isc_quota_t *quota, int max) {
+       LOCK(&quota->lock);
+       quota->max = max;
+       UNLOCK(&quota->lock);
+}
+
+isc_result_t
+isc_quota_reserve(isc_quota_t *quota) {
+       isc_result_t result;
+       LOCK(&quota->lock);
+       if (quota->max == 0 || quota->used < quota->max) {
+               if (quota->soft == 0 || quota->used < quota->soft)
+                       result = ISC_R_SUCCESS;
+               else
+                       result = ISC_R_SOFTQUOTA;
+               quota->used++;
+       } else
+               result = ISC_R_QUOTA;
+       UNLOCK(&quota->lock);
+       return (result);
+}
+
+void
+isc_quota_release(isc_quota_t *quota) {
+       LOCK(&quota->lock);
+       INSIST(quota->used > 0);
+       quota->used--;
+       UNLOCK(&quota->lock);
+}
+
+isc_result_t
+isc_quota_attach(isc_quota_t *quota, isc_quota_t **p)
+{
+       isc_result_t result;
+       INSIST(p != NULL && *p == NULL);
+       result = isc_quota_reserve(quota);
+       if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA)
+               *p = quota;
+       return (result);
+}
+
+void
+isc_quota_detach(isc_quota_t **p)
+{
+       INSIST(p != NULL && *p != NULL);
+       isc_quota_release(*p);
+       *p = NULL;
+}
diff --git a/lib/isc/radix.c b/lib/isc/radix.c
new file mode 100644 (file)
index 0000000..7786984
--- /dev/null
@@ -0,0 +1,706 @@
+/*
+ * Copyright (C) 2007-2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: radix.c,v 1.20.36.3 2009/01/18 23:47:41 tbox Exp $ */
+
+/*
+ * This source was adapted from MRT's RCS Ids:
+ * Id: radix.c,v 1.10.2.1 1999/11/29 05:16:24 masaki Exp
+ * Id: prefix.c,v 1.37.2.9 2000/03/10 02:53:19 labovit Exp
+ */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/types.h>
+#include <isc/util.h>
+#include <isc/radix.h>
+
+static isc_result_t
+_new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family,
+           void *dest, int bitlen);
+
+static void
+_deref_prefix(isc_mem_t *mctx, isc_prefix_t *prefix);
+
+static isc_result_t
+_ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix);
+
+static int
+_comp_with_mask(void *addr, void *dest, u_int mask);
+
+static void
+_clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func);
+
+static isc_result_t
+_new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, void *dest,
+           int bitlen)
+{
+       isc_prefix_t *prefix;
+
+       REQUIRE(target != NULL);
+
+       if (family != AF_INET6 && family != AF_INET && family != AF_UNSPEC)
+               return (ISC_R_NOTIMPLEMENTED);
+
+       prefix = isc_mem_get(mctx, sizeof(isc_prefix_t));
+       if (prefix == NULL)
+               return (ISC_R_NOMEMORY);
+
+       if (family == AF_INET6) {
+               prefix->bitlen = (bitlen >= 0) ? bitlen : 128;
+               memcpy(&prefix->add.sin6, dest, 16);
+       } else {
+               /* AF_UNSPEC is "any" or "none"--treat it as AF_INET */
+               prefix->bitlen = (bitlen >= 0) ? bitlen : 32;
+               memcpy(&prefix->add.sin, dest, 4);
+       }
+
+       prefix->family = family;
+
+       isc_refcount_init(&prefix->refcount, 1);
+
+       *target = prefix;
+       return (ISC_R_SUCCESS);
+}
+
+static void
+_deref_prefix(isc_mem_t *mctx, isc_prefix_t *prefix) {
+       int refs;
+
+       if (prefix == NULL)
+               return;
+
+       isc_refcount_decrement(&prefix->refcount, &refs);
+
+       if (refs <= 0) {
+               isc_refcount_destroy(&prefix->refcount);
+               isc_mem_put(mctx, prefix, sizeof(isc_prefix_t));
+       }
+}
+
+static isc_result_t
+_ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix) {
+       INSIST(prefix != NULL);
+       INSIST((prefix->family == AF_INET && prefix->bitlen <= 32) ||
+              (prefix->family == AF_INET6 && prefix->bitlen <= 128) ||
+              (prefix->family == AF_UNSPEC && prefix->bitlen == 0));
+       REQUIRE(target != NULL && *target == NULL);
+
+       /*
+        * If this prefix is a static allocation, copy it into new memory.
+        * (Note, the refcount still has to be destroyed by the calling
+        * routine.)
+        */
+       if (isc_refcount_current(&prefix->refcount) == 0) {
+               isc_result_t ret;
+               ret = _new_prefix(mctx, target, prefix->family,
+                                 &prefix->add, prefix->bitlen);
+               return ret;
+       }
+
+       isc_refcount_increment(&prefix->refcount, NULL);
+
+       *target = prefix;
+       return (ISC_R_SUCCESS);
+}
+
+static int
+_comp_with_mask(void *addr, void *dest, u_int mask) {
+
+       /* Mask length of zero matches everything */
+       if (mask == 0)
+               return (1);
+
+       if (memcmp(addr, dest, mask / 8) == 0) {
+               int n = mask / 8;
+               int m = ((~0) << (8 - (mask % 8)));
+
+               if ((mask % 8) == 0 ||
+                   (((u_char *)addr)[n] & m) == (((u_char *)dest)[n] & m))
+                       return (1);
+       }
+       return (0);
+}
+
+isc_result_t
+isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, int maxbits) {
+       isc_radix_tree_t *radix;
+
+       REQUIRE(target != NULL && *target == NULL);
+
+       radix = isc_mem_get(mctx, sizeof(isc_radix_tree_t));
+       if (radix == NULL)
+               return (ISC_R_NOMEMORY);
+
+       radix->mctx = mctx;
+       radix->maxbits = maxbits;
+       radix->head = NULL;
+       radix->num_active_node = 0;
+       radix->num_added_node = 0;
+       RUNTIME_CHECK(maxbits <= RADIX_MAXBITS); /* XXX */
+       radix->magic = RADIX_TREE_MAGIC;
+       *target = radix;
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * if func is supplied, it will be called as func(node->data)
+ * before deleting the node
+ */
+
+static void
+_clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) {
+
+       REQUIRE(radix != NULL);
+
+       if (radix->head != NULL) {
+
+               isc_radix_node_t *Xstack[RADIX_MAXBITS+1];
+               isc_radix_node_t **Xsp = Xstack;
+               isc_radix_node_t *Xrn = radix->head;
+
+               while (Xrn != NULL) {
+                       isc_radix_node_t *l = Xrn->l;
+                       isc_radix_node_t *r = Xrn->r;
+
+                       if (Xrn->prefix != NULL) {
+                               _deref_prefix(radix->mctx, Xrn->prefix);
+                               if (func != NULL && (Xrn->data[0] != NULL ||
+                                                    Xrn->data[1] != NULL))
+                                       func(Xrn->data);
+                       } else {
+                               INSIST(Xrn->data[0] == NULL &&
+                                      Xrn->data[1] == NULL);
+                       }
+
+                       isc_mem_put(radix->mctx, Xrn, sizeof(*Xrn));
+                       radix->num_active_node--;
+
+                       if (l != NULL) {
+                               if (r != NULL) {
+                                       *Xsp++ = r;
+                               }
+                               Xrn = l;
+                       } else if (r != NULL) {
+                               Xrn = r;
+                       } else if (Xsp != Xstack) {
+                               Xrn = *(--Xsp);
+                       } else {
+                               Xrn = NULL;
+                       }
+               }
+       }
+       RUNTIME_CHECK(radix->num_active_node == 0);
+}
+
+
+void
+isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func)
+{
+       REQUIRE(radix != NULL);
+       _clear_radix(radix, func);
+       isc_mem_put(radix->mctx, radix, sizeof(*radix));
+}
+
+
+/*
+ * func will be called as func(node->prefix, node->data)
+ */
+void
+isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func)
+{
+       isc_radix_node_t *node;
+
+       REQUIRE(func != NULL);
+
+       RADIX_WALK(radix->head, node) {
+               func(node->prefix, node->data);
+       } RADIX_WALK_END;
+}
+
+
+isc_result_t
+isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target,
+                isc_prefix_t *prefix)
+{
+       isc_radix_node_t *node;
+       isc_radix_node_t *stack[RADIX_MAXBITS + 1];
+       u_char *addr;
+       isc_uint32_t bitlen;
+       int tfamily = -1;
+       int cnt = 0;
+
+       REQUIRE(radix != NULL);
+       REQUIRE(prefix != NULL);
+       REQUIRE(target != NULL && *target == NULL);
+       RUNTIME_CHECK(prefix->bitlen <= radix->maxbits);
+
+       *target = NULL;
+
+       if (radix->head == NULL) {
+               return (ISC_R_NOTFOUND);
+       }
+
+       node = radix->head;
+       addr = isc_prefix_touchar(prefix);
+       bitlen = prefix->bitlen;
+
+       while (node->bit < bitlen) {
+               if (node->prefix)
+                       stack[cnt++] = node;
+
+               if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+                       node = node->r;
+               else
+                       node = node->l;
+
+               if (node == NULL)
+                       break;
+       }
+
+       if (node && node->prefix)
+               stack[cnt++] = node;
+
+       while (--cnt >= 0) {
+               node = stack[cnt];
+
+               if (_comp_with_mask(isc_prefix_tochar(node->prefix),
+                                   isc_prefix_tochar(prefix),
+                                   node->prefix->bitlen)) {
+                       if (node->node_num[ISC_IS6(prefix->family)] != -1 &&
+                                ((*target == NULL) ||
+                                 (*target)->node_num[ISC_IS6(tfamily)] >
+                                  node->node_num[ISC_IS6(prefix->family)])) {
+                               *target = node;
+                               tfamily = prefix->family;
+                       }
+               }
+       }
+
+       if (*target == NULL) {
+               return (ISC_R_NOTFOUND);
+       } else {
+               return (ISC_R_SUCCESS);
+       }
+}
+
+isc_result_t
+isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
+                isc_radix_node_t *source, isc_prefix_t *prefix)
+{
+       isc_radix_node_t *node, *new_node, *parent, *glue = NULL;
+       u_char *addr, *test_addr;
+       isc_uint32_t bitlen, fam, check_bit, differ_bit;
+       isc_uint32_t i, j, r;
+       isc_result_t result;
+
+       REQUIRE(radix != NULL);
+       REQUIRE(target != NULL && *target == NULL);
+       REQUIRE(prefix != NULL || (source != NULL && source->prefix != NULL));
+       RUNTIME_CHECK(prefix == NULL || prefix->bitlen <= radix->maxbits);
+
+       if (prefix == NULL)
+               prefix = source->prefix;
+
+       INSIST(prefix != NULL);
+
+       bitlen = prefix->bitlen;
+       fam = prefix->family;
+
+       if (radix->head == NULL) {
+               node = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t));
+               if (node == NULL)
+                       return (ISC_R_NOMEMORY);
+               node->bit = bitlen;
+               node->node_num[0] = node->node_num[1] = -1;
+               node->prefix = NULL;
+               result = _ref_prefix(radix->mctx, &node->prefix, prefix);
+               if (result != ISC_R_SUCCESS) {
+                       isc_mem_put(radix->mctx, node,
+                                   sizeof(isc_radix_node_t));
+                       return (result);
+               }
+               node->parent = NULL;
+               node->l = node->r = NULL;
+               if (source != NULL) {
+                       /*
+                        * If source is non-NULL, then we're merging in a
+                        * node from an existing radix tree.  To keep
+                        * the node_num values consistent, the calling
+                        * function will add the total number of nodes
+                        * added to num_added_node at the end of
+                        * the merge operation--we don't do it here.
+                        */
+                       if (source->node_num[0] != -1)
+                               node->node_num[0] = radix->num_added_node +
+                                                   source->node_num[0];
+                       if (source->node_num[1] != -1)
+                               node->node_num[1] = radix->num_added_node +
+                                                   source->node_num[1];
+                       node->data[0] = source->data[0];
+                       node->data[1] = source->data[1];
+               } else {
+                       if (fam == AF_UNSPEC) {
+                               /* "any" or "none" */
+                               node->node_num[0] = node->node_num[1] =
+                                       ++radix->num_added_node;
+                       } else {
+                               node->node_num[ISC_IS6(fam)] =
+                                       ++radix->num_added_node;
+                       }
+                       node->data[0] = NULL;
+                       node->data[1] = NULL;
+               }
+               radix->head = node;
+               radix->num_active_node++;
+               *target = node;
+               return (ISC_R_SUCCESS);
+       }
+
+       addr = isc_prefix_touchar(prefix);
+       node = radix->head;
+
+       while (node->bit < bitlen || node->prefix == NULL) {
+               if (node->bit < radix->maxbits &&
+                   BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+               {
+                       if (node->r == NULL)
+                               break;
+                       node = node->r;
+               } else {
+                       if (node->l == NULL)
+                               break;
+                       node = node->l;
+               }
+
+               INSIST(node != NULL);
+       }
+
+       INSIST(node->prefix != NULL);
+
+       test_addr = isc_prefix_touchar(node->prefix);
+       /* Find the first bit different. */
+       check_bit = (node->bit < bitlen) ? node->bit : bitlen;
+       differ_bit = 0;
+       for (i = 0; i*8 < check_bit; i++) {
+               if ((r = (addr[i] ^ test_addr[i])) == 0) {
+                       differ_bit = (i + 1) * 8;
+                       continue;
+               }
+               /* I know the better way, but for now. */
+               for (j = 0; j < 8; j++) {
+                       if (BIT_TEST (r, (0x80 >> j)))
+                               break;
+               }
+               /* Must be found. */
+               INSIST(j < 8);
+               differ_bit = i * 8 + j;
+               break;
+       }
+
+       if (differ_bit > check_bit)
+               differ_bit = check_bit;
+
+       parent = node->parent;
+       while (parent != NULL && parent->bit >= differ_bit) {
+               node = parent;
+               parent = node->parent;
+       }
+
+       if (differ_bit == bitlen && node->bit == bitlen) {
+               if (node->prefix != NULL) {
+                       /* Set node_num only if it hasn't been set before */
+                       if (source != NULL) {
+                               /* Merging node */
+                               if (node->node_num[0] == -1 &&
+                                   source->node_num[0] != -1) {
+                                       node->node_num[0] =
+                                               radix->num_added_node +
+                                               source->node_num[0];
+                                       node->data[0] = source->data[0];
+                               }
+                               if (node->node_num[1] == -1 &&
+                                   source->node_num[0] != -1) {
+                                       node->node_num[1] =
+                                               radix->num_added_node +
+                                               source->node_num[1];
+                                       node->data[1] = source->data[1];
+                               }
+                       } else {
+                               if (fam == AF_UNSPEC) {
+                                       /* "any" or "none" */
+                                       int next = radix->num_added_node + 1;
+                                       if (node->node_num[0] == -1) {
+                                               node->node_num[0] = next;
+                                               radix->num_added_node = next;
+                                       }
+                                       if (node->node_num[1] == -1) {
+                                               node->node_num[1] = next;
+                                               radix->num_added_node = next;
+                                       }
+                               } else {
+                                       if (node->node_num[ISC_IS6(fam)] == -1)
+                                               node->node_num[ISC_IS6(fam)]
+                                                  = ++radix->num_added_node;
+                               }
+                       }
+                       *target = node;
+                       return (ISC_R_SUCCESS);
+               } else {
+                       result =
+                               _ref_prefix(radix->mctx, &node->prefix, prefix);
+                       if (result != ISC_R_SUCCESS)
+                               return (result);
+               }
+               INSIST(node->data[0] == NULL && node->node_num[0] == -1 &&
+                      node->data[1] == NULL && node->node_num[1] == -1);
+               if (source != NULL) {
+                       /* Merging node */
+                       if (source->node_num[0] != -1) {
+                               node->node_num[0] = radix->num_added_node +
+                                                   source->node_num[0];
+                               node->data[0] = source->data[0];
+                       }
+                       if (source->node_num[1] != -1) {
+                               node->node_num[1] = radix->num_added_node +
+                                                   source->node_num[1];
+                               node->data[1] = source->data[1];
+                       }
+               } else {
+                       if (fam == AF_UNSPEC) {
+                               /* "any" or "none" */
+                               node->node_num[0] = node->node_num[1] =
+                                       ++radix->num_added_node;
+                       } else {
+                               node->node_num[ISC_IS6(fam)] =
+                                       ++radix->num_added_node;
+                       }
+               }
+               *target = node;
+               return (ISC_R_SUCCESS);
+       }
+
+       new_node = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t));
+       if (new_node == NULL)
+               return (ISC_R_NOMEMORY);
+       if (node->bit != differ_bit && bitlen != differ_bit) {
+               glue = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t));
+               if (glue == NULL) {
+                       isc_mem_put(radix->mctx, new_node,
+                                   sizeof(isc_radix_node_t));
+                       return (ISC_R_NOMEMORY);
+               }
+       }
+       new_node->bit = bitlen;
+       new_node->prefix = NULL;
+       result = _ref_prefix(radix->mctx, &new_node->prefix, prefix);
+       if (result != ISC_R_SUCCESS) {
+               isc_mem_put(radix->mctx, new_node, sizeof(isc_radix_node_t));
+               if (glue != NULL)
+                       isc_mem_put(radix->mctx, glue,
+                                   sizeof(isc_radix_node_t));
+               return (result);
+       }
+       new_node->parent = NULL;
+       new_node->l = new_node->r = NULL;
+       new_node->node_num[0] = new_node->node_num[1] = -1;
+       radix->num_active_node++;
+
+       if (source != NULL) {
+               /* Merging node */
+               if (source->node_num[0] != -1)
+                       new_node->node_num[0] = radix->num_added_node +
+                                               source->node_num[0];
+               if (source->node_num[1] != -1)
+                       new_node->node_num[1] = radix->num_added_node +
+                                               source->node_num[1];
+               new_node->data[0] = source->data[0];
+               new_node->data[1] = source->data[1];
+       } else {
+               if (fam == AF_UNSPEC) {
+                       /* "any" or "none" */
+                       new_node->node_num[0] = new_node->node_num[1] =
+                               ++radix->num_added_node;
+               } else {
+                       new_node->node_num[ISC_IS6(fam)] =
+                               ++radix->num_added_node;
+               }
+               new_node->data[0] = NULL;
+               new_node->data[1] = NULL;
+       }
+
+       if (node->bit == differ_bit) {
+               INSIST(glue == NULL);
+               new_node->parent = node;
+               if (node->bit < radix->maxbits &&
+                   BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
+               {
+                       INSIST(node->r == NULL);
+                       node->r = new_node;
+               } else {
+                       INSIST(node->l == NULL);
+                       node->l = new_node;
+               }
+               *target = new_node;
+               return (ISC_R_SUCCESS);
+       }
+
+       if (bitlen == differ_bit) {
+               INSIST(glue == NULL);
+               if (bitlen < radix->maxbits &&
+                   BIT_TEST(test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07))) {
+                       new_node->r = node;
+               } else {
+                       new_node->l = node;
+               }
+               new_node->parent = node->parent;
+               if (node->parent == NULL) {
+                       INSIST(radix->head == node);
+                       radix->head = new_node;
+               } else if (node->parent->r == node) {
+                       node->parent->r = new_node;
+               } else {
+                       node->parent->l = new_node;
+               }
+               node->parent = new_node;
+       } else {
+               INSIST(glue != NULL);
+               glue->bit = differ_bit;
+               glue->prefix = NULL;
+               glue->parent = node->parent;
+               glue->data[0] = glue->data[1] = NULL;
+               glue->node_num[0] = glue->node_num[1] = -1;
+               radix->num_active_node++;
+               if (differ_bit < radix->maxbits &&
+                   BIT_TEST(addr[differ_bit>>3], 0x80 >> (differ_bit & 07))) {
+                       glue->r = new_node;
+                       glue->l = node;
+               } else {
+                       glue->r = node;
+                       glue->l = new_node;
+               }
+               new_node->parent = glue;
+
+               if (node->parent == NULL) {
+                       INSIST(radix->head == node);
+                       radix->head = glue;
+               } else if (node->parent->r == node) {
+                       node->parent->r = glue;
+               } else {
+                       node->parent->l = glue;
+               }
+               node->parent = glue;
+       }
+
+       *target = new_node;
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) {
+       isc_radix_node_t *parent, *child;
+
+       REQUIRE(radix != NULL);
+       REQUIRE(node != NULL);
+
+       if (node->r && node->l) {
+               /*
+                * This might be a placeholder node -- have to check and
+                * make sure there is a prefix associated with it!
+                */
+               if (node->prefix != NULL)
+                       _deref_prefix(radix->mctx, node->prefix);
+
+               node->prefix = NULL;
+               node->data[0] = node->data[1] = NULL;
+               return;
+       }
+
+       if (node->r == NULL && node->l == NULL) {
+               parent = node->parent;
+               _deref_prefix(radix->mctx, node->prefix);
+               isc_mem_put(radix->mctx, node, sizeof(*node));
+               radix->num_active_node--;
+
+               if (parent == NULL) {
+                       INSIST(radix->head == node);
+                       radix->head = NULL;
+                       return;
+               }
+
+               if (parent->r == node) {
+                       parent->r = NULL;
+                       child = parent->l;
+               } else {
+                       INSIST(parent->l == node);
+                       parent->l = NULL;
+                       child = parent->r;
+               }
+
+               if (parent->prefix)
+                       return;
+
+               /* We need to remove parent too. */
+
+               if (parent->parent == NULL) {
+                       INSIST(radix->head == parent);
+                       radix->head = child;
+               } else if (parent->parent->r == parent) {
+                       parent->parent->r = child;
+               } else {
+                       INSIST(parent->parent->l == parent);
+                       parent->parent->l = child;
+               }
+               child->parent = parent->parent;
+               isc_mem_put(radix->mctx, parent, sizeof(*parent));
+               radix->num_active_node--;
+               return;
+       }
+
+       if (node->r) {
+               child = node->r;
+       } else {
+               INSIST(node->l != NULL);
+               child = node->l;
+       }
+       parent = node->parent;
+       child->parent = parent;
+
+       _deref_prefix(radix->mctx, node->prefix);
+       isc_mem_put(radix->mctx, node, sizeof(*node));
+       radix->num_active_node--;
+
+       if (parent == NULL) {
+               INSIST(radix->head == node);
+               radix->head = child;
+               return;
+       }
+
+       if (parent->r == node) {
+               parent->r = child;
+       } else {
+               INSIST(parent->l == node);
+               parent->l = child;
+       }
+}
+
+/*
+Local Variables:
+c-basic-offset: 4
+indent-tabs-mode: t
+End:
+*/
diff --git a/lib/isc/random.c b/lib/isc/random.c
new file mode 100644 (file)
index 0000000..0329abd
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: random.c,v 1.25 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <time.h>              /* Required for time(). */
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/random.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+initialize_rand(void)
+{
+#ifndef HAVE_ARC4RANDOM
+       unsigned int pid = getpid();
+       
+       /*
+        * The low bits of pid generally change faster.
+        * Xor them with the high bits of time which change slowly.
+        */
+       pid = ((pid << 16) & 0xffff0000) | ((pid >> 16) & 0xffff);
+
+       srand(time(NULL) ^ pid);
+#endif
+}
+
+static void
+initialize(void)
+{
+       RUNTIME_CHECK(isc_once_do(&once, initialize_rand) == ISC_R_SUCCESS);
+}
+
+void
+isc_random_seed(isc_uint32_t seed)
+{
+       initialize();
+
+#ifndef HAVE_ARC4RANDOM
+       srand(seed);
+#else
+       arc4random_addrandom((u_char *) &seed, sizeof(isc_uint32_t));
+#endif
+}
+
+void
+isc_random_get(isc_uint32_t *val)
+{
+       REQUIRE(val != NULL);
+
+       initialize();
+
+#ifndef HAVE_ARC4RANDOM
+       /*
+        * rand()'s lower bits are not random.
+        * rand()'s upper bit is zero.
+        */
+       *val = ((rand() >> 4) & 0xffff) | ((rand() << 12) & 0xffff0000);
+#else
+       *val = arc4random();
+#endif
+}
+
+isc_uint32_t
+isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) {
+       REQUIRE(jitter < max);
+       if (jitter == 0)
+               return (max);
+       else
+#ifndef HAVE_ARC4RANDOM
+               return (max - rand() % jitter);
+#else
+               return (max - arc4random() % jitter);
+#endif
+}
diff --git a/lib/isc/ratelimiter.c b/lib/isc/ratelimiter.c
new file mode 100644 (file)
index 0000000..07bcc7c
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ratelimiter.c,v 1.25 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/ratelimiter.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+typedef enum {
+       isc_ratelimiter_stalled = 0,
+       isc_ratelimiter_ratelimited = 1,
+       isc_ratelimiter_idle = 2,
+       isc_ratelimiter_shuttingdown = 3
+} isc_ratelimiter_state_t;
+
+struct isc_ratelimiter {
+       isc_mem_t *             mctx;
+       isc_mutex_t             lock;
+       int                     refs;
+       isc_task_t *            task;
+       isc_timer_t *           timer;
+       isc_interval_t          interval;
+       isc_uint32_t            pertic;
+       isc_ratelimiter_state_t state;
+       isc_event_t             shutdownevent;
+       ISC_LIST(isc_event_t)   pending;
+};
+
+#define ISC_RATELIMITEREVENT_SHUTDOWN (ISC_EVENTCLASS_RATELIMITER + 1)
+
+static void
+ratelimiter_tick(isc_task_t *task, isc_event_t *event);
+
+static void
+ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event);
+
+isc_result_t
+isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
+                      isc_task_t *task, isc_ratelimiter_t **ratelimiterp)
+{
+       isc_result_t result;
+       isc_ratelimiter_t *rl;
+       INSIST(ratelimiterp != NULL && *ratelimiterp == NULL);
+
+       rl = isc_mem_get(mctx, sizeof(*rl));
+       if (rl == NULL)
+               return ISC_R_NOMEMORY;
+       rl->mctx = mctx;
+       rl->refs = 1;
+       rl->task = task;
+       isc_interval_set(&rl->interval, 0, 0);
+       rl->timer = NULL;
+       rl->pertic = 1;
+       rl->state = isc_ratelimiter_idle;
+       ISC_LIST_INIT(rl->pending);
+
+       result = isc_mutex_init(&rl->lock);
+       if (result != ISC_R_SUCCESS)
+               goto free_mem;
+       result = isc_timer_create(timermgr, isc_timertype_inactive,
+                                 NULL, NULL, rl->task, ratelimiter_tick,
+                                 rl, &rl->timer);
+       if (result != ISC_R_SUCCESS)
+               goto free_mutex;
+
+       /*
+        * Increment the reference count to indicate that we may
+        * (soon) have events outstanding.
+        */
+       rl->refs++;
+
+       ISC_EVENT_INIT(&rl->shutdownevent,
+                      sizeof(isc_event_t),
+                      0, NULL, ISC_RATELIMITEREVENT_SHUTDOWN,
+                      ratelimiter_shutdowncomplete, rl, rl, NULL, NULL);
+
+       *ratelimiterp = rl;
+       return (ISC_R_SUCCESS);
+
+free_mutex:
+       DESTROYLOCK(&rl->lock);
+free_mem:
+       isc_mem_put(mctx, rl, sizeof(*rl));
+       return (result);
+}
+
+isc_result_t
+isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) {
+       isc_result_t result = ISC_R_SUCCESS;
+       LOCK(&rl->lock);
+       rl->interval = *interval;
+       /*
+        * If the timer is currently running, change its rate.
+        */
+        if (rl->state == isc_ratelimiter_ratelimited) {
+               result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL,
+                                        &rl->interval, ISC_FALSE);
+       }
+       UNLOCK(&rl->lock);
+       return (result);
+}
+
+void
+isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t pertic) {
+       if (pertic == 0)
+               pertic = 1;
+       rl->pertic = pertic;
+}
+
+isc_result_t
+isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
+                       isc_event_t **eventp)
+{
+       isc_result_t result = ISC_R_SUCCESS;
+       isc_event_t *ev;
+
+       REQUIRE(eventp != NULL && *eventp != NULL);
+       REQUIRE(task != NULL);
+       ev = *eventp;
+       REQUIRE(ev->ev_sender == NULL);
+
+       LOCK(&rl->lock);
+        if (rl->state == isc_ratelimiter_ratelimited ||
+           rl->state == isc_ratelimiter_stalled) {
+               isc_event_t *ev = *eventp;
+               ev->ev_sender = task;
+                ISC_LIST_APPEND(rl->pending, ev, ev_link);
+               *eventp = NULL;
+        } else if (rl->state == isc_ratelimiter_idle) {
+               result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL,
+                                        &rl->interval, ISC_FALSE);
+               if (result == ISC_R_SUCCESS) {
+                       ev->ev_sender = task;
+                       rl->state = isc_ratelimiter_ratelimited;
+               }
+       } else {
+               INSIST(rl->state == isc_ratelimiter_shuttingdown);
+               result = ISC_R_SHUTTINGDOWN;
+       }
+       UNLOCK(&rl->lock);
+       if (*eventp != NULL && result == ISC_R_SUCCESS)
+               isc_task_send(task, eventp);
+       return (result);
+}
+
+static void
+ratelimiter_tick(isc_task_t *task, isc_event_t *event) {
+       isc_result_t result = ISC_R_SUCCESS;
+       isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg;
+       isc_event_t *p;
+       isc_uint32_t pertic;
+
+       UNUSED(task);
+
+       isc_event_free(&event);
+
+       pertic = rl->pertic;
+        while (pertic != 0) {
+               pertic--;
+               LOCK(&rl->lock);
+               p = ISC_LIST_HEAD(rl->pending);
+               if (p != NULL) {
+                       /*
+                        * There is work to do.  Let's do it after unlocking.
+                        */
+                       ISC_LIST_UNLINK(rl->pending, p, ev_link);
+               } else {
+                       /*
+                        * No work left to do.  Stop the timer so that we don't
+                        * waste resources by having it fire periodically.
+                        */
+                       result = isc_timer_reset(rl->timer,
+                                                isc_timertype_inactive,
+                                                NULL, NULL, ISC_FALSE);
+                       RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                       rl->state = isc_ratelimiter_idle;
+                       pertic = 0;     /* Force the loop to exit. */
+               }
+               UNLOCK(&rl->lock);
+               if (p != NULL) {
+                       isc_task_t *evtask = p->ev_sender;
+                       isc_task_send(evtask, &p);
+               }
+               INSIST(p == NULL);
+       }
+}
+
+void
+isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) {
+       isc_event_t *ev;
+       isc_task_t *task;
+       LOCK(&rl->lock);
+       rl->state = isc_ratelimiter_shuttingdown;
+       (void)isc_timer_reset(rl->timer, isc_timertype_inactive,
+                             NULL, NULL, ISC_FALSE);
+       while ((ev = ISC_LIST_HEAD(rl->pending)) != NULL) {
+               ISC_LIST_UNLINK(rl->pending, ev, ev_link);
+               ev->ev_attributes |= ISC_EVENTATTR_CANCELED;
+               task = ev->ev_sender;
+               isc_task_send(task, &ev);
+       }
+       isc_timer_detach(&rl->timer);
+       /*
+        * Send an event to our task.  The delivery of this event
+        * indicates that no more timer events will be delivered.
+        */
+       ev = &rl->shutdownevent;
+       isc_task_send(rl->task, &ev);
+
+       UNLOCK(&rl->lock);
+}
+
+static void
+ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event) {
+       isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg;
+
+       UNUSED(task);
+
+       isc_ratelimiter_detach(&rl);
+}
+
+static void
+ratelimiter_free(isc_ratelimiter_t *rl) {
+       DESTROYLOCK(&rl->lock);
+       isc_mem_put(rl->mctx, rl, sizeof(*rl));
+}
+
+void
+isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target) {
+       REQUIRE(source != NULL);
+       REQUIRE(target != NULL && *target == NULL);
+
+       LOCK(&source->lock);
+       REQUIRE(source->refs > 0);
+       source->refs++;
+       INSIST(source->refs > 0);
+       UNLOCK(&source->lock);
+       *target = source;
+}
+
+void
+isc_ratelimiter_detach(isc_ratelimiter_t **rlp) {
+       isc_ratelimiter_t *rl = *rlp;
+       isc_boolean_t free_now = ISC_FALSE;
+
+       LOCK(&rl->lock);
+       REQUIRE(rl->refs > 0);
+       rl->refs--;
+       if (rl->refs == 0)
+               free_now = ISC_TRUE;
+       UNLOCK(&rl->lock);
+
+       if (free_now)
+               ratelimiter_free(rl);
+
+       *rlp = NULL;
+}
+
+isc_result_t
+isc_ratelimiter_stall(isc_ratelimiter_t *rl) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       LOCK(&rl->lock);
+       switch (rl->state) {
+       case isc_ratelimiter_shuttingdown:
+               result = ISC_R_SHUTTINGDOWN;
+               break;
+       case isc_ratelimiter_ratelimited:
+               result = isc_timer_reset(rl->timer, isc_timertype_inactive,
+                                        NULL, NULL, ISC_FALSE);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       case isc_ratelimiter_idle:
+       case isc_ratelimiter_stalled:
+               rl->state = isc_ratelimiter_stalled;
+               break;
+       }
+       UNLOCK(&rl->lock);
+       return (result);
+}
+
+isc_result_t
+isc_ratelimiter_release(isc_ratelimiter_t *rl) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       LOCK(&rl->lock);
+       switch (rl->state) {
+       case isc_ratelimiter_shuttingdown:
+               result = ISC_R_SHUTTINGDOWN;
+               break;
+       case isc_ratelimiter_stalled:
+               if (!ISC_LIST_EMPTY(rl->pending)) {
+                       result = isc_timer_reset(rl->timer,
+                                                isc_timertype_ticker, NULL,
+                                                &rl->interval, ISC_FALSE);
+                       if (result == ISC_R_SUCCESS)
+                               rl->state = isc_ratelimiter_ratelimited;
+               } else 
+                       rl->state = isc_ratelimiter_idle;
+               break;
+       case isc_ratelimiter_ratelimited:
+       case isc_ratelimiter_idle:
+               break;
+       }
+       UNLOCK(&rl->lock);
+       return (result);
+}
diff --git a/lib/isc/refcount.c b/lib/isc/refcount.c
new file mode 100644 (file)
index 0000000..36dfff2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: refcount.c,v 1.5 2007/06/19 23:47:17 tbox Exp $ */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/mutex.h>
+#include <isc/refcount.h>
+#include <isc/result.h>
+
+isc_result_t
+isc_refcount_init(isc_refcount_t *ref, unsigned int n) {
+       REQUIRE(ref != NULL);
+
+       ref->refs = n;
+#if defined(ISC_PLATFORM_USETHREADS) && !defined(ISC_PLATFORM_HAVEXADD)
+       return (isc_mutex_init(&ref->lock));
+#else
+       return (ISC_R_SUCCESS);
+#endif
+}
diff --git a/lib/isc/region.c b/lib/isc/region.c
new file mode 100644 (file)
index 0000000..cf64979
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: region.c,v 1.7 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/region.h>
+#include <isc/util.h>
+
+int
+isc_region_compare(isc_region_t *r1, isc_region_t *r2) {
+       unsigned int l;
+       int result;
+
+       REQUIRE(r1 != NULL);
+       REQUIRE(r2 != NULL);
+              
+       l = (r1->length < r2->length) ? r1->length : r2->length;
+
+       if ((result = memcmp(r1->base, r2->base, l)) != 0)
+               return ((result < 0) ? -1 : 1);
+       else
+               return ((r1->length == r2->length) ? 0 :
+                       (r1->length < r2->length) ? -1 : 1);
+}
diff --git a/lib/isc/result.c b/lib/isc/result.c
new file mode 100644 (file)
index 0000000..5713580
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: result.c,v 1.71 2008/09/25 04:02:39 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <isc/lib.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/resultclass.h>
+#include <isc/util.h>
+
+typedef struct resulttable {
+       unsigned int                            base;
+       unsigned int                            last;
+       const char **                           text;
+       isc_msgcat_t *                          msgcat;
+       int                                     set;
+       ISC_LINK(struct resulttable)            link;
+} resulttable;
+
+static const char *text[ISC_R_NRESULTS] = {
+       "success",                              /*%< 0 */
+       "out of memory",                        /*%< 1 */
+       "timed out",                            /*%< 2 */
+       "no available threads",                 /*%< 3 */
+       "address not available",                /*%< 4 */
+       "address in use",                       /*%< 5 */
+       "permission denied",                    /*%< 6 */
+       "no pending connections",               /*%< 7 */
+       "network unreachable",                  /*%< 8 */
+       "host unreachable",                     /*%< 9 */
+       "network down",                         /*%< 10 */
+       "host down",                            /*%< 11 */
+       "connection refused",                   /*%< 12 */
+       "not enough free resources",            /*%< 13 */
+       "end of file",                          /*%< 14 */
+       "socket already bound",                 /*%< 15 */
+       "reload",                               /*%< 16 */
+       "lock busy",                            /*%< 17 */
+       "already exists",                       /*%< 18 */
+       "ran out of space",                     /*%< 19 */
+       "operation canceled",                   /*%< 20 */
+       "socket is not bound",                  /*%< 21 */
+       "shutting down",                        /*%< 22 */
+       "not found",                            /*%< 23 */
+       "unexpected end of input",              /*%< 24 */
+       "failure",                              /*%< 25 */
+       "I/O error",                            /*%< 26 */
+       "not implemented",                      /*%< 27 */
+       "unbalanced parentheses",               /*%< 28 */
+       "no more",                              /*%< 29 */
+       "invalid file",                         /*%< 30 */
+       "bad base64 encoding",                  /*%< 31 */
+       "unexpected token",                     /*%< 32 */
+       "quota reached",                        /*%< 33 */
+       "unexpected error",                     /*%< 34 */
+       "already running",                      /*%< 35 */
+       "ignore",                               /*%< 36 */
+       "address mask not contiguous",          /*%< 37 */
+       "file not found",                       /*%< 38 */
+       "file already exists",                  /*%< 39 */
+       "socket is not connected",              /*%< 40 */
+       "out of range",                         /*%< 41 */
+       "out of entropy",                       /*%< 42 */
+       "invalid use of multicast address",     /*%< 43 */
+       "not a file",                           /*%< 44 */
+       "not a directory",                      /*%< 45 */
+       "queue is full",                        /*%< 46 */
+       "address family mismatch",              /*%< 47 */
+       "address family not supported",         /*%< 48 */
+       "bad hex encoding",                     /*%< 49 */
+       "too many open files",                  /*%< 50 */
+       "not blocking",                         /*%< 51 */
+       "unbalanced quotes",                    /*%< 52 */
+       "operation in progress",                /*%< 53 */
+       "connection reset",                     /*%< 54 */
+       "soft quota reached",                   /*%< 55 */
+       "not a valid number",                   /*%< 56 */
+       "disabled",                             /*%< 57 */
+       "max size",                             /*%< 58 */
+       "invalid address format",               /*%< 59 */
+       "bad base32 encoding",                  /*%< 60 */
+};
+
+#define ISC_RESULT_RESULTSET                   2
+#define ISC_RESULT_UNAVAILABLESET              3
+
+static isc_once_t                              once = ISC_ONCE_INIT;
+static ISC_LIST(resulttable)                   tables;
+static isc_mutex_t                             lock;
+
+static isc_result_t
+register_table(unsigned int base, unsigned int nresults, const char **text,
+              isc_msgcat_t *msgcat, int set)
+{
+       resulttable *table;
+
+       REQUIRE(base % ISC_RESULTCLASS_SIZE == 0);
+       REQUIRE(nresults <= ISC_RESULTCLASS_SIZE);
+       REQUIRE(text != NULL);
+
+       /*
+        * We use malloc() here because we we want to be able to use
+        * isc_result_totext() even if there is no memory context.
+        */
+       table = malloc(sizeof(*table));
+       if (table == NULL)
+               return (ISC_R_NOMEMORY);
+       table->base = base;
+       table->last = base + nresults - 1;
+       table->text = text;
+       table->msgcat = msgcat;
+       table->set = set;
+       ISC_LINK_INIT(table, link);
+
+       LOCK(&lock);
+
+       ISC_LIST_APPEND(tables, table, link);
+
+       UNLOCK(&lock);
+
+       return (ISC_R_SUCCESS);
+}
+
+static void
+initialize_action(void) {
+       isc_result_t result;
+
+       RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
+       ISC_LIST_INIT(tables);
+
+       result = register_table(ISC_RESULTCLASS_ISC, ISC_R_NRESULTS, text,
+                               isc_msgcat, ISC_RESULT_RESULTSET);
+       if (result != ISC_R_SUCCESS)
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "register_table() %s: %u",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"),
+                                result);
+}
+
+static void
+initialize(void) {
+       isc_lib_initmsgcat();
+       RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+const char *
+isc_result_totext(isc_result_t result) {
+       resulttable *table;
+       const char *text, *default_text;
+       int index;
+
+       initialize();
+
+       LOCK(&lock);
+
+       text = NULL;
+       for (table = ISC_LIST_HEAD(tables);
+            table != NULL;
+            table = ISC_LIST_NEXT(table, link)) {
+               if (result >= table->base && result <= table->last) {
+                       index = (int)(result - table->base);
+                       default_text = table->text[index];
+                       /*
+                        * Note: we use 'index + 1' as the message number
+                        * instead of index because isc_msgcat_get() requires
+                        * the message number to be > 0.
+                        */
+                       text = isc_msgcat_get(table->msgcat, table->set,
+                                             index + 1, default_text);
+                       break;
+               }
+       }
+       if (text == NULL)
+               text = isc_msgcat_get(isc_msgcat, ISC_RESULT_UNAVAILABLESET,
+                                     1, "(result code text not available)");
+
+       UNLOCK(&lock);
+
+       return (text);
+}
+
+isc_result_t
+isc_result_register(unsigned int base, unsigned int nresults,
+                   const char **text, isc_msgcat_t *msgcat, int set)
+{
+       initialize();
+
+       return (register_table(base, nresults, text, msgcat, set));
+}
diff --git a/lib/isc/rwlock.c b/lib/isc/rwlock.c
new file mode 100644 (file)
index 0000000..ca8e83d
--- /dev/null
@@ -0,0 +1,808 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: rwlock.c,v 1.44.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/atomic.h>
+#include <isc/magic.h>
+#include <isc/msgs.h>
+#include <isc/platform.h>
+#include <isc/rwlock.h>
+#include <isc/util.h>
+
+#define RWLOCK_MAGIC           ISC_MAGIC('R', 'W', 'L', 'k')
+#define VALID_RWLOCK(rwl)      ISC_MAGIC_VALID(rwl, RWLOCK_MAGIC)
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+#ifndef RWLOCK_DEFAULT_READ_QUOTA
+#define RWLOCK_DEFAULT_READ_QUOTA 4
+#endif
+
+#ifndef RWLOCK_DEFAULT_WRITE_QUOTA
+#define RWLOCK_DEFAULT_WRITE_QUOTA 4
+#endif
+
+#ifdef ISC_RWLOCK_TRACE
+#include <stdio.h>             /* Required for fprintf/stderr. */
+#include <isc/thread.h>                /* Required for isc_thread_self(). */
+
+static void
+print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+       fprintf(stderr,
+               isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                              ISC_MSG_PRINTLOCK,
+                              "rwlock %p thread %lu %s(%s): %s, %u active, "
+                              "%u granted, %u rwaiting, %u wwaiting\n"),
+               rwl, isc_thread_self(), operation,
+               (type == isc_rwlocktype_read ?
+                isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                               ISC_MSG_READ, "read") :
+                isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                               ISC_MSG_WRITE, "write")),
+               (rwl->type == isc_rwlocktype_read ?
+                isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                               ISC_MSG_READING, "reading") :
+                isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                               ISC_MSG_WRITING, "writing")),
+               rwl->active, rwl->granted, rwl->readers_waiting,
+               rwl->writers_waiting);
+}
+#endif
+
+isc_result_t
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+               unsigned int write_quota)
+{
+       isc_result_t result;
+
+       REQUIRE(rwl != NULL);
+
+       /*
+        * In case there's trouble initializing, we zero magic now.  If all
+        * goes well, we'll set it to RWLOCK_MAGIC.
+        */
+       rwl->magic = 0;
+
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+       rwl->write_requests = 0;
+       rwl->write_completions = 0;
+       rwl->cnt_and_flag = 0;
+       rwl->readers_waiting = 0;
+       rwl->write_granted = 0;
+       if (read_quota != 0) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "read quota is not supported");
+       }
+       if (write_quota == 0)
+               write_quota = RWLOCK_DEFAULT_WRITE_QUOTA;
+       rwl->write_quota = write_quota;
+#else
+       rwl->type = isc_rwlocktype_read;
+       rwl->original = isc_rwlocktype_none;
+       rwl->active = 0;
+       rwl->granted = 0;
+       rwl->readers_waiting = 0;
+       rwl->writers_waiting = 0;
+       if (read_quota == 0)
+               read_quota = RWLOCK_DEFAULT_READ_QUOTA;
+       rwl->read_quota = read_quota;
+       if (write_quota == 0)
+               write_quota = RWLOCK_DEFAULT_WRITE_QUOTA;
+       rwl->write_quota = write_quota;
+#endif
+
+       result = isc_mutex_init(&rwl->lock);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       result = isc_condition_init(&rwl->readable);
+       if (result != ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_condition_init(readable) %s: %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"),
+                                isc_result_totext(result));
+               result = ISC_R_UNEXPECTED;
+               goto destroy_lock;
+       }
+       result = isc_condition_init(&rwl->writeable);
+       if (result != ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_condition_init(writeable) %s: %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"),
+                                isc_result_totext(result));
+               result = ISC_R_UNEXPECTED;
+               goto destroy_rcond;
+       }
+
+       rwl->magic = RWLOCK_MAGIC;
+
+       return (ISC_R_SUCCESS);
+
+  destroy_rcond:
+       (void)isc_condition_destroy(&rwl->readable);
+  destroy_lock:
+       DESTROYLOCK(&rwl->lock);
+
+       return (result);
+}
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl) {
+       REQUIRE(VALID_RWLOCK(rwl));
+
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+       REQUIRE(rwl->write_requests == rwl->write_completions &&
+               rwl->cnt_and_flag == 0 && rwl->readers_waiting == 0);
+#else
+       LOCK(&rwl->lock);
+       REQUIRE(rwl->active == 0 &&
+               rwl->readers_waiting == 0 &&
+               rwl->writers_waiting == 0);
+       UNLOCK(&rwl->lock);
+#endif
+
+       rwl->magic = 0;
+       (void)isc_condition_destroy(&rwl->readable);
+       (void)isc_condition_destroy(&rwl->writeable);
+       DESTROYLOCK(&rwl->lock);
+}
+
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+
+/*
+ * When some architecture-dependent atomic operations are available,
+ * rwlock can be more efficient than the generic algorithm defined below.
+ * The basic algorithm is described in the following URL:
+ *   http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
+ *
+ * The key is to use the following integer variables modified atomically:
+ *   write_requests, write_completions, and cnt_and_flag.
+ *
+ * write_requests and write_completions act as a waiting queue for writers
+ * in order to ensure the FIFO order.  Both variables begin with the initial
+ * value of 0.  When a new writer tries to get a write lock, it increments
+ * write_requests and gets the previous value of the variable as a "ticket".
+ * When write_completions reaches the ticket number, the new writer can start
+ * writing.  When the writer completes its work, it increments
+ * write_completions so that another new writer can start working.  If the
+ * write_requests is not equal to write_completions, it means a writer is now
+ * working or waiting.  In this case, a new readers cannot start reading, or
+ * in other words, this algorithm basically prefers writers.
+ *
+ * cnt_and_flag is a "lock" shared by all readers and writers.  This integer
+ * variable is a kind of structure with two members: writer_flag (1 bit) and
+ * reader_count (31 bits).  The writer_flag shows whether a writer is working,
+ * and the reader_count shows the number of readers currently working or almost
+ * ready for working.  A writer who has the current "ticket" tries to get the
+ * lock by exclusively setting the writer_flag to 1, provided that the whole
+ * 32-bit is 0 (meaning no readers or writers working).  On the other hand,
+ * a new reader tries to increment the "reader_count" field provided that
+ * the writer_flag is 0 (meaning there is no writer working).
+ *
+ * If some of the above operations fail, the reader or the writer sleeps
+ * until the related condition changes.  When a working reader or writer
+ * completes its work, some readers or writers are sleeping, and the condition
+ * that suspended the reader or writer has changed, it wakes up the sleeping
+ * readers or writers.
+ *
+ * As already noted, this algorithm basically prefers writers.  In order to
+ * prevent readers from starving, however, the algorithm also introduces the
+ * "writer quota" (Q).  When Q consecutive writers have completed their work,
+ * suspending readers, the last writer will wake up the readers, even if a new
+ * writer is waiting.
+ *
+ * Implementation specific note: due to the combination of atomic operations
+ * and a mutex lock, ordering between the atomic operation and locks can be
+ * very sensitive in some cases.  In particular, it is generally very important
+ * to check the atomic variable that requires a reader or writer to sleep after
+ * locking the mutex and before actually sleeping; otherwise, it could be very
+ * likely to cause a deadlock.  For example, assume "var" is a variable
+ * atomically modified, then the corresponding code would be:
+ *     if (var == need_sleep) {
+ *             LOCK(lock);
+ *             if (var == need_sleep)
+ *                     WAIT(cond, lock);
+ *             UNLOCK(lock);
+ *     }
+ * The second check is important, since "var" is protected by the atomic
+ * operation, not by the mutex, and can be changed just before sleeping.
+ * (The first "if" could be omitted, but this is also important in order to
+ * make the code efficient by avoiding the use of the mutex unless it is
+ * really necessary.)
+ */
+
+#define WRITER_ACTIVE  0x1
+#define READER_INCR    0x2
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+       isc_int32_t cntflag;
+
+       REQUIRE(VALID_RWLOCK(rwl));
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_PRELOCK, "prelock"), rwl, type);
+#endif
+
+       if (type == isc_rwlocktype_read) {
+               if (rwl->write_requests != rwl->write_completions) {
+                       /* there is a waiting or active writer */
+                       LOCK(&rwl->lock);
+                       if (rwl->write_requests != rwl->write_completions) {
+                               rwl->readers_waiting++;
+                               WAIT(&rwl->readable, &rwl->lock);
+                               rwl->readers_waiting--;
+                       }
+                       UNLOCK(&rwl->lock);
+               }
+
+               cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+               while (1) {
+                       if ((rwl->cnt_and_flag & WRITER_ACTIVE) == 0)
+                               break;
+
+                       /* A writer is still working */
+                       LOCK(&rwl->lock);
+                       rwl->readers_waiting++;
+                       if ((rwl->cnt_and_flag & WRITER_ACTIVE) != 0)
+                               WAIT(&rwl->readable, &rwl->lock);
+                       rwl->readers_waiting--;
+                       UNLOCK(&rwl->lock);
+
+                       /*
+                        * Typically, the reader should be able to get a lock
+                        * at this stage:
+                        *   (1) there should have been no pending writer when
+                        *       the reader was trying to increment the
+                        *       counter; otherwise, the writer should be in
+                        *       the waiting queue, preventing the reader from
+                        *       proceeding to this point.
+                        *   (2) once the reader increments the counter, no
+                        *       more writer can get a lock.
+                        * Still, it is possible another writer can work at
+                        * this point, e.g. in the following scenario:
+                        *   A previous writer unlocks the writer lock.
+                        *   This reader proceeds to point (1).
+                        *   A new writer appears, and gets a new lock before
+                        *   the reader increments the counter.
+                        *   The reader then increments the counter.
+                        *   The previous writer notices there is a waiting
+                        *   reader who is almost ready, and wakes it up.
+                        * So, the reader needs to confirm whether it can now
+                        * read explicitly (thus we loop).  Note that this is
+                        * not an infinite process, since the reader has
+                        * incremented the counter at this point.
+                        */
+               }
+
+               /*
+                * If we are temporarily preferred to writers due to the writer
+                * quota, reset the condition (race among readers doesn't
+                * matter).
+                */
+               rwl->write_granted = 0;
+       } else {
+               isc_int32_t prev_writer;
+
+               /* enter the waiting queue, and wait for our turn */
+               prev_writer = isc_atomic_xadd(&rwl->write_requests, 1);
+               while (rwl->write_completions != prev_writer) {
+                       LOCK(&rwl->lock);
+                       if (rwl->write_completions != prev_writer) {
+                               WAIT(&rwl->writeable, &rwl->lock);
+                               UNLOCK(&rwl->lock);
+                               continue;
+                       }
+                       UNLOCK(&rwl->lock);
+                       break;
+               }
+
+               while (1) {
+                       cntflag = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0,
+                                                    WRITER_ACTIVE);
+                       if (cntflag == 0)
+                               break;
+
+                       /* Another active reader or writer is working. */
+                       LOCK(&rwl->lock);
+                       if (rwl->cnt_and_flag != 0)
+                               WAIT(&rwl->writeable, &rwl->lock);
+                       UNLOCK(&rwl->lock);
+               }
+
+               INSIST((rwl->cnt_and_flag & WRITER_ACTIVE) != 0);
+               rwl->write_granted++;
+       }
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_POSTLOCK, "postlock"), rwl, type);
+#endif
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+       isc_int32_t cntflag;
+
+       REQUIRE(VALID_RWLOCK(rwl));
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_PRELOCK, "prelock"), rwl, type);
+#endif
+
+       if (type == isc_rwlocktype_read) {
+               /* If a writer is waiting or working, we fail. */
+               if (rwl->write_requests != rwl->write_completions)
+                       return (ISC_R_LOCKBUSY);
+
+               /* Otherwise, be ready for reading. */
+               cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+               if ((cntflag & WRITER_ACTIVE) != 0) {
+                       /*
+                        * A writer is working.  We lose, and cancel the read
+                        * request.
+                        */
+                       cntflag = isc_atomic_xadd(&rwl->cnt_and_flag,
+                                                 -READER_INCR);
+                       /*
+                        * If no other readers are waiting and we've suspended
+                        * new writers in this short period, wake them up.
+                        */
+                       if (cntflag == READER_INCR &&
+                           rwl->write_completions != rwl->write_requests) {
+                               LOCK(&rwl->lock);
+                               BROADCAST(&rwl->writeable);
+                               UNLOCK(&rwl->lock);
+                       }
+
+                       return (ISC_R_LOCKBUSY);
+               }
+       } else {
+               /* Try locking without entering the waiting queue. */
+               cntflag = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0,
+                                            WRITER_ACTIVE);
+               if (cntflag != 0)
+                       return (ISC_R_LOCKBUSY);
+
+               /*
+                * XXXJT: jump into the queue, possibly breaking the writer
+                * order.
+                */
+               (void)isc_atomic_xadd(&rwl->write_completions, -1);
+
+               rwl->write_granted++;
+       }
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_POSTLOCK, "postlock"), rwl, type);
+#endif
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
+       isc_int32_t prevcnt;
+
+       REQUIRE(VALID_RWLOCK(rwl));
+
+       /* Try to acquire write access. */
+       prevcnt = isc_atomic_cmpxchg(&rwl->cnt_and_flag,
+                                    READER_INCR, WRITER_ACTIVE);
+       /*
+        * There must have been no writer, and there must have been at least
+        * one reader.
+        */
+       INSIST((prevcnt & WRITER_ACTIVE) == 0 &&
+              (prevcnt & ~WRITER_ACTIVE) != 0);
+
+       if (prevcnt == READER_INCR) {
+               /*
+                * We are the only reader and have been upgraded.
+                * Now jump into the head of the writer waiting queue.
+                */
+               (void)isc_atomic_xadd(&rwl->write_completions, -1);
+       } else
+               return (ISC_R_LOCKBUSY);
+
+       return (ISC_R_SUCCESS);
+
+}
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+       isc_int32_t prev_readers;
+
+       REQUIRE(VALID_RWLOCK(rwl));
+
+       /* Become an active reader. */
+       prev_readers = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR);
+       /* We must have been a writer. */
+       INSIST((prev_readers & WRITER_ACTIVE) != 0);
+
+       /* Complete write */
+       (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE);
+       (void)isc_atomic_xadd(&rwl->write_completions, 1);
+
+       /* Resume other readers */
+       LOCK(&rwl->lock);
+       if (rwl->readers_waiting > 0)
+               BROADCAST(&rwl->readable);
+       UNLOCK(&rwl->lock);
+}
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+       isc_int32_t prev_cnt;
+
+       REQUIRE(VALID_RWLOCK(rwl));
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_PREUNLOCK, "preunlock"), rwl, type);
+#endif
+
+       if (type == isc_rwlocktype_read) {
+               prev_cnt = isc_atomic_xadd(&rwl->cnt_and_flag, -READER_INCR);
+
+               /*
+                * If we're the last reader and any writers are waiting, wake
+                * them up.  We need to wake up all of them to ensure the
+                * FIFO order.
+                */
+               if (prev_cnt == READER_INCR &&
+                   rwl->write_completions != rwl->write_requests) {
+                       LOCK(&rwl->lock);
+                       BROADCAST(&rwl->writeable);
+                       UNLOCK(&rwl->lock);
+               }
+       } else {
+               isc_boolean_t wakeup_writers = ISC_TRUE;
+
+               /*
+                * Reset the flag, and (implicitly) tell other writers
+                * we are done.
+                */
+               (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE);
+               (void)isc_atomic_xadd(&rwl->write_completions, 1);
+
+               if (rwl->write_granted >= rwl->write_quota ||
+                   rwl->write_requests == rwl->write_completions ||
+                   (rwl->cnt_and_flag & ~WRITER_ACTIVE) != 0) {
+                       /*
+                        * We have passed the write quota, no writer is
+                        * waiting, or some readers are almost ready, pending
+                        * possible writers.  Note that the last case can
+                        * happen even if write_requests != write_completions
+                        * (which means a new writer in the queue), so we need
+                        * to catch the case explicitly.
+                        */
+                       LOCK(&rwl->lock);
+                       if (rwl->readers_waiting > 0) {
+                               wakeup_writers = ISC_FALSE;
+                               BROADCAST(&rwl->readable);
+                       }
+                       UNLOCK(&rwl->lock);
+               }
+
+               if (rwl->write_requests != rwl->write_completions &&
+                   wakeup_writers) {
+                       LOCK(&rwl->lock);
+                       BROADCAST(&rwl->writeable);
+                       UNLOCK(&rwl->lock);
+               }
+       }
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_POSTUNLOCK, "postunlock"),
+                  rwl, type);
+#endif
+
+       return (ISC_R_SUCCESS);
+}
+
+#else /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+
+static isc_result_t
+doit(isc_rwlock_t *rwl, isc_rwlocktype_t type, isc_boolean_t nonblock) {
+       isc_boolean_t skip = ISC_FALSE;
+       isc_boolean_t done = ISC_FALSE;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(VALID_RWLOCK(rwl));
+
+       LOCK(&rwl->lock);
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_PRELOCK, "prelock"), rwl, type);
+#endif
+
+       if (type == isc_rwlocktype_read) {
+               if (rwl->readers_waiting != 0)
+                       skip = ISC_TRUE;
+               while (!done) {
+                       if (!skip &&
+                           ((rwl->active == 0 ||
+                             (rwl->type == isc_rwlocktype_read &&
+                              (rwl->writers_waiting == 0 ||
+                               rwl->granted < rwl->read_quota)))))
+                       {
+                               rwl->type = isc_rwlocktype_read;
+                               rwl->active++;
+                               rwl->granted++;
+                               done = ISC_TRUE;
+                       } else if (nonblock) {
+                               result = ISC_R_LOCKBUSY;
+                               done = ISC_TRUE;
+                       } else {
+                               skip = ISC_FALSE;
+                               rwl->readers_waiting++;
+                               WAIT(&rwl->readable, &rwl->lock);
+                               rwl->readers_waiting--;
+                       }
+               }
+       } else {
+               if (rwl->writers_waiting != 0)
+                       skip = ISC_TRUE;
+               while (!done) {
+                       if (!skip && rwl->active == 0) {
+                               rwl->type = isc_rwlocktype_write;
+                               rwl->active = 1;
+                               rwl->granted++;
+                               done = ISC_TRUE;
+                       } else if (nonblock) {
+                               result = ISC_R_LOCKBUSY;
+                               done = ISC_TRUE;
+                       } else {
+                               skip = ISC_FALSE;
+                               rwl->writers_waiting++;
+                               WAIT(&rwl->writeable, &rwl->lock);
+                               rwl->writers_waiting--;
+                       }
+               }
+       }
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_POSTLOCK, "postlock"), rwl, type);
+#endif
+
+       UNLOCK(&rwl->lock);
+
+       return (result);
+}
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+       return (doit(rwl, type, ISC_FALSE));
+}
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+       return (doit(rwl, type, ISC_TRUE));
+}
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(VALID_RWLOCK(rwl));
+       LOCK(&rwl->lock);
+       REQUIRE(rwl->type == isc_rwlocktype_read);
+       REQUIRE(rwl->active != 0);
+
+       /* If we are the only reader then succeed. */
+       if (rwl->active == 1) {
+               rwl->original = (rwl->original == isc_rwlocktype_none) ?
+                               isc_rwlocktype_read : isc_rwlocktype_none;
+               rwl->type = isc_rwlocktype_write;
+       } else
+               result = ISC_R_LOCKBUSY;
+
+       UNLOCK(&rwl->lock);
+       return (result);
+}
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+
+       REQUIRE(VALID_RWLOCK(rwl));
+       LOCK(&rwl->lock);
+       REQUIRE(rwl->type == isc_rwlocktype_write);
+       REQUIRE(rwl->active == 1);
+
+       rwl->type = isc_rwlocktype_read;
+       rwl->original = (rwl->original == isc_rwlocktype_none) ?
+                       isc_rwlocktype_write : isc_rwlocktype_none;
+       /*
+        * Resume processing any read request that were blocked when
+        * we upgraded.
+        */
+       if (rwl->original == isc_rwlocktype_none &&
+           (rwl->writers_waiting == 0 || rwl->granted < rwl->read_quota) &&
+           rwl->readers_waiting > 0)
+               BROADCAST(&rwl->readable);
+
+       UNLOCK(&rwl->lock);
+}
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+
+       REQUIRE(VALID_RWLOCK(rwl));
+       LOCK(&rwl->lock);
+       REQUIRE(rwl->type == type);
+
+       UNUSED(type);
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_PREUNLOCK, "preunlock"), rwl, type);
+#endif
+
+       INSIST(rwl->active > 0);
+       rwl->active--;
+       if (rwl->active == 0) {
+               if (rwl->original != isc_rwlocktype_none) {
+                       rwl->type = rwl->original;
+                       rwl->original = isc_rwlocktype_none;
+               }
+               if (rwl->type == isc_rwlocktype_read) {
+                       rwl->granted = 0;
+                       if (rwl->writers_waiting > 0) {
+                               rwl->type = isc_rwlocktype_write;
+                               SIGNAL(&rwl->writeable);
+                       } else if (rwl->readers_waiting > 0) {
+                               /* Does this case ever happen? */
+                               BROADCAST(&rwl->readable);
+                       }
+               } else {
+                       if (rwl->readers_waiting > 0) {
+                               if (rwl->writers_waiting > 0 &&
+                                   rwl->granted < rwl->write_quota) {
+                                       SIGNAL(&rwl->writeable);
+                               } else {
+                                       rwl->granted = 0;
+                                       rwl->type = isc_rwlocktype_read;
+                                       BROADCAST(&rwl->readable);
+                               }
+                       } else if (rwl->writers_waiting > 0) {
+                               rwl->granted = 0;
+                               SIGNAL(&rwl->writeable);
+                       } else {
+                               rwl->granted = 0;
+                       }
+               }
+       }
+       INSIST(rwl->original == isc_rwlocktype_none);
+
+#ifdef ISC_RWLOCK_TRACE
+       print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+                                 ISC_MSG_POSTUNLOCK, "postunlock"),
+                  rwl, type);
+#endif
+
+       UNLOCK(&rwl->lock);
+
+       return (ISC_R_SUCCESS);
+}
+
+#endif /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */
+#else /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+               unsigned int write_quota)
+{
+       REQUIRE(rwl != NULL);
+
+       UNUSED(read_quota);
+       UNUSED(write_quota);
+
+       rwl->type = isc_rwlocktype_read;
+       rwl->active = 0;
+       rwl->magic = RWLOCK_MAGIC;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+       REQUIRE(VALID_RWLOCK(rwl));
+
+       if (type == isc_rwlocktype_read) {
+               if (rwl->type != isc_rwlocktype_read && rwl->active != 0)
+                       return (ISC_R_LOCKBUSY);
+               rwl->type = isc_rwlocktype_read;
+               rwl->active++;
+       } else {
+               if (rwl->active != 0)
+                       return (ISC_R_LOCKBUSY);
+               rwl->type = isc_rwlocktype_write;
+               rwl->active = 1;
+       }
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+       return (isc_rwlock_lock(rwl, type));
+}
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(VALID_RWLOCK(rwl));
+       REQUIRE(rwl->type == isc_rwlocktype_read);
+       REQUIRE(rwl->active != 0);
+
+       /* If we are the only reader then succeed. */
+       if (rwl->active == 1)
+               rwl->type = isc_rwlocktype_write;
+       else
+               result = ISC_R_LOCKBUSY;
+       return (result);
+}
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+
+       REQUIRE(VALID_RWLOCK(rwl));
+       REQUIRE(rwl->type == isc_rwlocktype_write);
+       REQUIRE(rwl->active == 1);
+
+       rwl->type = isc_rwlocktype_read;
+}
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+       REQUIRE(VALID_RWLOCK(rwl));
+       REQUIRE(rwl->type == type);
+
+       UNUSED(type);
+
+       INSIST(rwl->active > 0);
+       rwl->active--;
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl) {
+       REQUIRE(rwl != NULL);
+       REQUIRE(rwl->active == 0);
+       rwl->magic = 0;
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
diff --git a/lib/isc/serial.c b/lib/isc/serial.c
new file mode 100644 (file)
index 0000000..b43aac7
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: serial.c,v 1.12 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/serial.h>
+
+isc_boolean_t
+isc_serial_lt(isc_uint32_t a, isc_uint32_t b) {
+       /*
+        * Undefined => ISC_FALSE
+        */
+       if (a == (b ^ 0x80000000U))
+               return (ISC_FALSE);
+       return (((isc_int32_t)(a - b) < 0) ? ISC_TRUE : ISC_FALSE);
+}
+
+isc_boolean_t
+isc_serial_gt(isc_uint32_t a, isc_uint32_t b) {
+       return (((isc_int32_t)(a - b) > 0) ? ISC_TRUE : ISC_FALSE);
+}
+
+isc_boolean_t
+isc_serial_le(isc_uint32_t a, isc_uint32_t b) {
+       return ((a == b) ? ISC_TRUE : isc_serial_lt(a, b));
+}
+
+isc_boolean_t
+isc_serial_ge(isc_uint32_t a, isc_uint32_t b) {
+       return ((a == b) ? ISC_TRUE : isc_serial_gt(a, b));
+}
+
+isc_boolean_t
+isc_serial_eq(isc_uint32_t a, isc_uint32_t b) {
+       return ((a == b) ? ISC_TRUE : ISC_FALSE);
+}
+
+isc_boolean_t
+isc_serial_ne(isc_uint32_t a, isc_uint32_t b) {
+       return ((a != b) ? ISC_TRUE : ISC_FALSE);
+}
diff --git a/lib/isc/sha1.c b/lib/isc/sha1.c
new file mode 100644 (file)
index 0000000..3575288
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sha1.c,v 1.18 2007/06/19 23:47:17 tbox Exp $ */
+
+/*     $NetBSD: sha1.c,v 1.5 2000/01/22 22:19:14 mycroft Exp $ */
+/*     $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $       */
+
+/*! \file
+ * SHA-1 in C
+ * \author By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ * \verbatim
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ *   A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ *   84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ *   34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ * \endverbatim
+ */
+
+#include "config.h"
+
+#include <isc/assertions.h>
+#include <isc/sha1.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/*@{*/
+/*!
+ * blk0() and blk() perform the initial expand.
+ * I got the idea of expanding during the round function from SSLeay
+ */
+#if !defined(WORDS_BIGENDIAN)
+# define blk0(i) \
+       (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \
+        | (rol(block->l[i], 8) & 0x00FF00FF))
+#else
+# define blk0(i) block->l[i]
+#endif
+#define blk(i) \
+       (block->l[i & 15] = rol(block->l[(i + 13) & 15] \
+                               ^ block->l[(i + 8) & 15] \
+                               ^ block->l[(i + 2) & 15] \
+                               ^ block->l[i & 15], 1))
+
+/*@}*/
+/*@{*/
+/*!
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ */
+#define R0(v,w,x,y,z,i) \
+       z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
+       w = rol(w, 30);
+#define R1(v,w,x,y,z,i) \
+       z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
+       w = rol(w, 30);
+#define R2(v,w,x,y,z,i) \
+       z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
+       w = rol(w, 30);
+#define R3(v,w,x,y,z,i) \
+       z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
+       w = rol(w, 30);
+#define R4(v,w,x,y,z,i) \
+       z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
+       w = rol(w, 30);
+
+/*@}*/
+
+typedef union {
+       unsigned char c[64];
+       unsigned int l[16];
+} CHAR64LONG16;
+
+#ifdef __sparc_v9__
+static void do_R01(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c,
+                  isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *);
+static void do_R2(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c,
+                 isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *);
+static void do_R3(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c,
+                 isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *);
+static void do_R4(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c,
+                 isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *);
+
+#define nR0(v,w,x,y,z,i) R0(*v,*w,*x,*y,*z,i)
+#define nR1(v,w,x,y,z,i) R1(*v,*w,*x,*y,*z,i)
+#define nR2(v,w,x,y,z,i) R2(*v,*w,*x,*y,*z,i)
+#define nR3(v,w,x,y,z,i) R3(*v,*w,*x,*y,*z,i)
+#define nR4(v,w,x,y,z,i) R4(*v,*w,*x,*y,*z,i)
+
+static void
+do_R01(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d,
+       isc_uint32_t *e, CHAR64LONG16 *block)
+{
+       nR0(a,b,c,d,e, 0); nR0(e,a,b,c,d, 1); nR0(d,e,a,b,c, 2);
+       nR0(c,d,e,a,b, 3); nR0(b,c,d,e,a, 4); nR0(a,b,c,d,e, 5);
+       nR0(e,a,b,c,d, 6); nR0(d,e,a,b,c, 7); nR0(c,d,e,a,b, 8);
+       nR0(b,c,d,e,a, 9); nR0(a,b,c,d,e,10); nR0(e,a,b,c,d,11);
+       nR0(d,e,a,b,c,12); nR0(c,d,e,a,b,13); nR0(b,c,d,e,a,14);
+       nR0(a,b,c,d,e,15); nR1(e,a,b,c,d,16); nR1(d,e,a,b,c,17);
+       nR1(c,d,e,a,b,18); nR1(b,c,d,e,a,19);
+}
+
+static void
+do_R2(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d,
+      isc_uint32_t *e, CHAR64LONG16 *block)
+{
+       nR2(a,b,c,d,e,20); nR2(e,a,b,c,d,21); nR2(d,e,a,b,c,22);
+       nR2(c,d,e,a,b,23); nR2(b,c,d,e,a,24); nR2(a,b,c,d,e,25);
+       nR2(e,a,b,c,d,26); nR2(d,e,a,b,c,27); nR2(c,d,e,a,b,28);
+       nR2(b,c,d,e,a,29); nR2(a,b,c,d,e,30); nR2(e,a,b,c,d,31);
+       nR2(d,e,a,b,c,32); nR2(c,d,e,a,b,33); nR2(b,c,d,e,a,34);
+       nR2(a,b,c,d,e,35); nR2(e,a,b,c,d,36); nR2(d,e,a,b,c,37);
+       nR2(c,d,e,a,b,38); nR2(b,c,d,e,a,39);
+}
+
+static void
+do_R3(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d,
+      isc_uint32_t *e, CHAR64LONG16 *block)
+{
+       nR3(a,b,c,d,e,40); nR3(e,a,b,c,d,41); nR3(d,e,a,b,c,42);
+       nR3(c,d,e,a,b,43); nR3(b,c,d,e,a,44); nR3(a,b,c,d,e,45);
+       nR3(e,a,b,c,d,46); nR3(d,e,a,b,c,47); nR3(c,d,e,a,b,48);
+       nR3(b,c,d,e,a,49); nR3(a,b,c,d,e,50); nR3(e,a,b,c,d,51);
+       nR3(d,e,a,b,c,52); nR3(c,d,e,a,b,53); nR3(b,c,d,e,a,54);
+       nR3(a,b,c,d,e,55); nR3(e,a,b,c,d,56); nR3(d,e,a,b,c,57);
+       nR3(c,d,e,a,b,58); nR3(b,c,d,e,a,59);
+}
+
+static void
+do_R4(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d,
+      isc_uint32_t *e, CHAR64LONG16 *block)
+{
+       nR4(a,b,c,d,e,60); nR4(e,a,b,c,d,61); nR4(d,e,a,b,c,62);
+       nR4(c,d,e,a,b,63); nR4(b,c,d,e,a,64); nR4(a,b,c,d,e,65);
+       nR4(e,a,b,c,d,66); nR4(d,e,a,b,c,67); nR4(c,d,e,a,b,68);
+       nR4(b,c,d,e,a,69); nR4(a,b,c,d,e,70); nR4(e,a,b,c,d,71);
+       nR4(d,e,a,b,c,72); nR4(c,d,e,a,b,73); nR4(b,c,d,e,a,74);
+       nR4(a,b,c,d,e,75); nR4(e,a,b,c,d,76); nR4(d,e,a,b,c,77);
+       nR4(c,d,e,a,b,78); nR4(b,c,d,e,a,79);
+}
+#endif
+
+/*!
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+static void
+transform(isc_uint32_t state[5], const unsigned char buffer[64]) {
+       isc_uint32_t a, b, c, d, e;
+       CHAR64LONG16 *block;
+       CHAR64LONG16 workspace;
+
+       INSIST(buffer != NULL);
+       INSIST(state != NULL);
+
+       block = &workspace;
+       (void)memcpy(block, buffer, 64);
+
+       /* Copy context->state[] to working vars */
+       a = state[0];
+       b = state[1];
+       c = state[2];
+       d = state[3];
+       e = state[4];
+
+#ifdef __sparc_v9__
+       do_R01(&a, &b, &c, &d, &e, block);
+       do_R2(&a, &b, &c, &d, &e, block);
+       do_R3(&a, &b, &c, &d, &e, block);
+       do_R4(&a, &b, &c, &d, &e, block);
+#else
+       /* 4 rounds of 20 operations each. Loop unrolled. */
+       R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+       R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+       R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+       R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+       R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+       R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+       R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+       R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+       R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+       R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+       R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+       R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+       R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+       R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+       R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+       R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+       R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+       R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+       R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+       R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+#endif
+
+       /* Add the working vars back into context.state[] */
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+       state[4] += e;
+
+       /* Wipe variables */
+       a = b = c = d = e = 0;
+}
+
+
+/*!
+ * isc_sha1_init - Initialize new context
+ */
+void
+isc_sha1_init(isc_sha1_t *context)
+{
+       INSIST(context != NULL);
+
+       /* SHA1 initialization constants */
+       context->state[0] = 0x67452301;
+       context->state[1] = 0xEFCDAB89;
+       context->state[2] = 0x98BADCFE;
+       context->state[3] = 0x10325476;
+       context->state[4] = 0xC3D2E1F0;
+       context->count[0] = 0;
+       context->count[1] = 0;
+}
+
+void
+isc_sha1_invalidate(isc_sha1_t *context) {
+       memset(context, 0, sizeof(isc_sha1_t));
+}
+
+/*!
+ * Run your data through this.
+ */
+void
+isc_sha1_update(isc_sha1_t *context, const unsigned char *data,
+               unsigned int len)
+{
+       unsigned int i, j;
+
+       INSIST(context != 0);
+       INSIST(data != 0);
+
+       j = context->count[0];
+       if ((context->count[0] += len << 3) < j)
+               context->count[1] += (len >> 29) + 1;
+       j = (j >> 3) & 63;
+       if ((j + len) > 63) {
+               (void)memcpy(&context->buffer[j], data, (i = 64 - j));
+               transform(context->state, context->buffer);
+               for (; i + 63 < len; i += 64)
+                       transform(context->state, &data[i]);
+               j = 0;
+       } else {
+               i = 0;
+       }
+
+       (void)memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/*!
+ * Add padding and return the message digest.
+ */
+
+static const unsigned char final_200 = 128;
+static const unsigned char final_0 = 0;
+
+void
+isc_sha1_final(isc_sha1_t *context, unsigned char *digest) {
+       unsigned int i;
+       unsigned char finalcount[8];
+
+       INSIST(digest != 0);
+       INSIST(context != 0);
+
+       for (i = 0; i < 8; i++) {
+               /* Endian independent */
+               finalcount[i] = (unsigned char)
+                       ((context->count[(i >= 4 ? 0 : 1)]
+                         >> ((3 - (i & 3)) * 8)) & 255);
+       }
+
+       isc_sha1_update(context, &final_200, 1);
+       while ((context->count[0] & 504) != 448)
+               isc_sha1_update(context, &final_0, 1);
+       /* The next Update should cause a transform() */
+       isc_sha1_update(context, finalcount, 8);
+
+       if (digest) {
+               for (i = 0; i < 20; i++)
+                       digest[i] = (unsigned char)
+                               ((context->state[i >> 2]
+                                 >> ((3 - (i & 3)) * 8)) & 255);
+       }
+
+       memset(context, 0, sizeof(isc_sha1_t));
+}
diff --git a/lib/isc/sha2.c b/lib/isc/sha2.c
new file mode 100644 (file)
index 0000000..6cd900d
--- /dev/null
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (C) 2005-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: sha2.c,v 1.13.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+/*     $FreeBSD: src/sys/crypto/sha2/sha2.c,v 1.2.2.2 2002/03/05 08:36:47 ume Exp $    */
+/*     $KAME: sha2.c,v 1.8 2001/11/08 01:07:52 itojun Exp $    */
+
+/*
+ * sha2.c
+ *
+ * Version 1.0.0beta1
+ *
+ * Written by Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright 2000 Aaron D. Gifford.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+
+#include <config.h>
+
+#include <isc/assertions.h>
+#include <isc/sha2.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/*
+ * UNROLLED TRANSFORM LOOP NOTE:
+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
+ * loop version for the hash transform rounds (defined using macros
+ * later in this file).  Either define on the command line, for example:
+ *
+ *   cc -DISC_SHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
+ *
+ * or define below:
+ *
+ *   \#define ISC_SHA2_UNROLL_TRANSFORM
+ *
+ */
+
+/*** SHA-256/384/512 Machine Architecture Definitions *****************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * Please make sure that your system defines BYTE_ORDER.  If your
+ * architecture is little-endian, make sure it also defines
+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
+ * equivalent.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ *   \#define LITTLE_ENDIAN 1234
+ *   \#define BIG_ENDIAN    4321
+ *
+ * And for little-endian machines, add:
+ *
+ *   \#define BYTE_ORDER LITTLE_ENDIAN
+ *
+ * Or for big-endian machines:
+ *
+ *   \#define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
+#ifndef BYTE_ORDER
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+#ifdef WORDS_BIGENDIAN
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#else
+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
+#endif
+#endif
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+/* NOTE: Most of these are in sha2.h */
+#define ISC_SHA256_SHORT_BLOCK_LENGTH  (ISC_SHA256_BLOCK_LENGTH - 8)
+#define ISC_SHA384_SHORT_BLOCK_LENGTH  (ISC_SHA384_BLOCK_LENGTH - 16)
+#define ISC_SHA512_SHORT_BLOCK_LENGTH  (ISC_SHA512_BLOCK_LENGTH - 16)
+
+
+/*** ENDIAN REVERSAL MACROS *******************************************/
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define REVERSE32(w,x) { \
+       isc_uint32_t tmp = (w); \
+       tmp = (tmp >> 16) | (tmp << 16); \
+       (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
+}
+#ifdef WIN32
+#define REVERSE64(w,x) { \
+       isc_uint64_t tmp = (w); \
+       tmp = (tmp >> 32) | (tmp << 32); \
+       tmp = ((tmp & 0xff00ff00ff00ff00UL) >> 8) | \
+             ((tmp & 0x00ff00ff00ff00ffUL) << 8); \
+       (x) = ((tmp & 0xffff0000ffff0000UL) >> 16) | \
+             ((tmp & 0x0000ffff0000ffffUL) << 16); \
+}
+#else
+#define REVERSE64(w,x) { \
+       isc_uint64_t tmp = (w); \
+       tmp = (tmp >> 32) | (tmp << 32); \
+       tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
+             ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
+       (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
+             ((tmp & 0x0000ffff0000ffffULL) << 16); \
+}
+#endif
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+       (w)[0] += (isc_uint64_t)(n); \
+       if ((w)[0] < (n)) { \
+               (w)[1]++; \
+       } \
+}
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ *   NOTE:  The naming of R and S appears backwards here (R is a SHIFT and
+ *   S is a ROTATION) because the SHA-256/384/512 description document
+ *   (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ *   same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x)                 ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define S32(b,x)       (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x)       (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z)      (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z)     (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-256: */
+#define Sigma0_256(x)  (S32(2,  (x)) ^ S32(13, (x)) ^ S32(22, (x)))
+#define Sigma1_256(x)  (S32(6,  (x)) ^ S32(11, (x)) ^ S32(25, (x)))
+#define sigma0_256(x)  (S32(7,  (x)) ^ S32(18, (x)) ^ R(3 ,   (x)))
+#define sigma1_256(x)  (S32(17, (x)) ^ S32(19, (x)) ^ R(10,   (x)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x)  (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x)  (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x)  (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7,   (x)))
+#define sigma1_512(x)  (S64(19, (x)) ^ S64(61, (x)) ^ R( 6,   (x)))
+
+/*** INTERNAL FUNCTION PROTOTYPES *************************************/
+/* NOTE: These should not be accessed directly from outside this
+ * library -- they are intended for private internal visibility/use
+ * only.
+ */
+void isc_sha512_last(isc_sha512_t *);
+void isc_sha256_transform(isc_sha256_t *, const isc_uint32_t*);
+void isc_sha512_transform(isc_sha512_t *, const isc_uint64_t*);
+
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-224 and SHA-256: */
+static const isc_uint32_t K256[64] = {
+       0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+       0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+       0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+       0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+       0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+       0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+       0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+       0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+       0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+       0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+       0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+       0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+       0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+       0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+       0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+       0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Initial hash value H for SHA-224: */
+static const isc_uint32_t sha224_initial_hash_value[8] = {
+       0xc1059ed8UL,
+       0x367cd507UL,
+       0x3070dd17UL,
+       0xf70e5939UL,
+       0xffc00b31UL,
+       0x68581511UL,
+       0x64f98fa7UL,
+       0xbefa4fa4UL
+};
+
+/* Initial hash value H for SHA-256: */
+static const isc_uint32_t sha256_initial_hash_value[8] = {
+       0x6a09e667UL,
+       0xbb67ae85UL,
+       0x3c6ef372UL,
+       0xa54ff53aUL,
+       0x510e527fUL,
+       0x9b05688cUL,
+       0x1f83d9abUL,
+       0x5be0cd19UL
+};
+
+#ifdef WIN32
+/* Hash constant words K for SHA-384 and SHA-512: */
+static const isc_uint64_t K512[80] = {
+       0x428a2f98d728ae22UL, 0x7137449123ef65cdUL,
+       0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL,
+       0x3956c25bf348b538UL, 0x59f111f1b605d019UL,
+       0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL,
+       0xd807aa98a3030242UL, 0x12835b0145706fbeUL,
+       0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL,
+       0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL,
+       0x9bdc06a725c71235UL, 0xc19bf174cf692694UL,
+       0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL,
+       0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL,
+       0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL,
+       0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL,
+       0x983e5152ee66dfabUL, 0xa831c66d2db43210UL,
+       0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL,
+       0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL,
+       0x06ca6351e003826fUL, 0x142929670a0e6e70UL,
+       0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL,
+       0x4d2c6dfc5ac42aedUL, 0x53380d139d95b3dfUL,
+       0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL,
+       0x81c2c92e47edaee6UL, 0x92722c851482353bUL,
+       0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL,
+       0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL,
+       0xd192e819d6ef5218UL, 0xd69906245565a910UL,
+       0xf40e35855771202aUL, 0x106aa07032bbd1b8UL,
+       0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL,
+       0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL,
+       0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL,
+       0x5b9cca4f7763e373UL, 0x682e6ff3d6b2b8a3UL,
+       0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL,
+       0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL,
+       0x90befffa23631e28UL, 0xa4506cebde82bde9UL,
+       0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL,
+       0xca273eceea26619cUL, 0xd186b8c721c0c207UL,
+       0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL,
+       0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL,
+       0x113f9804bef90daeUL, 0x1b710b35131c471bUL,
+       0x28db77f523047d84UL, 0x32caab7b40c72493UL,
+       0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL,
+       0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL,
+       0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL
+};
+
+/* Initial hash value H for SHA-384: */
+static const isc_uint64_t sha384_initial_hash_value[8] = {
+       0xcbbb9d5dc1059ed8UL,
+       0x629a292a367cd507UL,
+       0x9159015a3070dd17UL,
+       0x152fecd8f70e5939UL,
+       0x67332667ffc00b31UL,
+       0x8eb44a8768581511UL,
+       0xdb0c2e0d64f98fa7UL,
+       0x47b5481dbefa4fa4UL
+};
+
+/* Initial hash value H for SHA-512: */
+static const isc_uint64_t sha512_initial_hash_value[8] = {
+       0x6a09e667f3bcc908U,
+       0xbb67ae8584caa73bUL,
+       0x3c6ef372fe94f82bUL,
+       0xa54ff53a5f1d36f1UL,
+       0x510e527fade682d1UL,
+       0x9b05688c2b3e6c1fUL,
+       0x1f83d9abfb41bd6bUL,
+       0x5be0cd19137e2179UL
+};
+#else
+/* Hash constant words K for SHA-384 and SHA-512: */
+static const isc_uint64_t K512[80] = {
+       0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+       0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+       0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+       0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+       0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+       0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+       0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+       0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+       0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+       0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+       0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+       0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+       0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+       0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+       0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+       0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+       0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+       0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+       0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+       0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+       0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+       0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+       0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+       0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+       0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+       0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+       0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+       0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+       0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+       0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+       0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+       0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+       0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+       0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+       0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+       0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+       0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+       0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+       0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+       0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* Initial hash value H for SHA-384: */
+static const isc_uint64_t sha384_initial_hash_value[8] = {
+       0xcbbb9d5dc1059ed8ULL,
+       0x629a292a367cd507ULL,
+       0x9159015a3070dd17ULL,
+       0x152fecd8f70e5939ULL,
+       0x67332667ffc00b31ULL,
+       0x8eb44a8768581511ULL,
+       0xdb0c2e0d64f98fa7ULL,
+       0x47b5481dbefa4fa4ULL
+};
+
+/* Initial hash value H for SHA-512: */
+static const isc_uint64_t sha512_initial_hash_value[8] = {
+       0x6a09e667f3bcc908ULL,
+       0xbb67ae8584caa73bULL,
+       0x3c6ef372fe94f82bULL,
+       0xa54ff53a5f1d36f1ULL,
+       0x510e527fade682d1ULL,
+       0x9b05688c2b3e6c1fULL,
+       0x1f83d9abfb41bd6bULL,
+       0x5be0cd19137e2179ULL
+};
+#endif
+
+/*
+ * Constant used by SHA256/384/512_End() functions for converting the
+ * digest to a readable hexadecimal character string:
+ */
+static const char *sha2_hex_digits = "0123456789abcdef";
+
+
+
+/*** SHA-224: *********************************************************/
+void
+isc_sha224_init(isc_sha224_t *context) {
+       if (context == (isc_sha256_t *)0) {
+               return;
+       }
+       memcpy(context->state, sha224_initial_hash_value,
+              ISC_SHA256_DIGESTLENGTH);
+       memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH);
+       context->bitcount = 0;
+}
+
+void
+isc_sha224_update(isc_sha224_t *context, const isc_uint8_t* data, size_t len) {
+       isc_sha256_update((isc_sha256_t *)context, data, len);
+}
+
+void
+isc_sha224_final(isc_uint8_t digest[], isc_sha224_t *context) {
+       isc_uint8_t sha256_digest[ISC_SHA256_DIGESTLENGTH];
+       isc_sha256_final(sha256_digest, (isc_sha256_t *)context);
+       memcpy(digest, sha256_digest, ISC_SHA224_DIGESTLENGTH);
+       memset(sha256_digest, 0, ISC_SHA256_DIGESTLENGTH);
+}
+
+char *
+isc_sha224_end(isc_sha224_t *context, char buffer[]) {
+       isc_uint8_t     digest[ISC_SHA224_DIGESTLENGTH], *d = digest;
+       unsigned int    i;
+
+       /* Sanity check: */
+       REQUIRE(context != (isc_sha224_t *)0);
+
+       if (buffer != (char*)0) {
+               isc_sha224_final(digest, context);
+
+               for (i = 0; i < ISC_SHA224_DIGESTLENGTH; i++) {
+                       *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+                       *buffer++ = sha2_hex_digits[*d & 0x0f];
+                       d++;
+               }
+               *buffer = (char)0;
+       } else {
+               memset(context, 0, sizeof(context));
+       }
+       memset(digest, 0, ISC_SHA224_DIGESTLENGTH);
+       return buffer;
+}
+
+char*
+isc_sha224_data(const isc_uint8_t *data, size_t len,
+               char digest[ISC_SHA224_DIGESTSTRINGLENGTH])
+{
+       isc_sha224_t context;
+
+       isc_sha224_init(&context);
+       isc_sha224_update(&context, data, len);
+       return (isc_sha224_end(&context, digest));
+}
+
+/*** SHA-256: *********************************************************/
+void
+isc_sha256_init(isc_sha256_t *context) {
+       if (context == (isc_sha256_t *)0) {
+               return;
+       }
+       memcpy(context->state, sha256_initial_hash_value,
+              ISC_SHA256_DIGESTLENGTH);
+       memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH);
+       context->bitcount = 0;
+}
+
+#ifdef ISC_SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)      \
+       REVERSE32(*data++, W256[j]); \
+       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+            K256[j] + W256[j]; \
+       (d) += T1; \
+       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+       j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)      \
+       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+            K256[j] + (W256[j] = *data++); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+       j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256(a,b,c,d,e,f,g,h)      \
+       s0 = W256[(j+1)&0x0f]; \
+       s0 = sigma0_256(s0); \
+       s1 = W256[(j+14)&0x0f]; \
+       s1 = sigma1_256(s1); \
+       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
+            (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+       j++
+
+void isc_sha256_transform(isc_sha256_t *context, const isc_uint32_t* data) {
+       isc_uint32_t    a, b, c, d, e, f, g, h, s0, s1;
+       isc_uint32_t    T1, *W256;
+       int             j;
+
+       W256 = (isc_uint32_t*)context->buffer;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+               /* Rounds 0 to 15 (unrolled): */
+               ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+               ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+               ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+               ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+               ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+               ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+               ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+               ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+       } while (j < 16);
+
+       /* Now for the remaining rounds to 64: */
+       do {
+               ROUND256(a,b,c,d,e,f,g,h);
+               ROUND256(h,a,b,c,d,e,f,g);
+               ROUND256(g,h,a,b,c,d,e,f);
+               ROUND256(f,g,h,a,b,c,d,e);
+               ROUND256(e,f,g,h,a,b,c,d);
+               ROUND256(d,e,f,g,h,a,b,c);
+               ROUND256(c,d,e,f,g,h,a,b);
+               ROUND256(b,c,d,e,f,g,h,a);
+       } while (j < 64);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void
+isc_sha256_transform(isc_sha256_t *context, const isc_uint32_t* data) {
+       isc_uint32_t    a, b, c, d, e, f, g, h, s0, s1;
+       isc_uint32_t    T1, T2, *W256;
+       int             j;
+
+       W256 = (isc_uint32_t*)context->buffer;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+               /* Copy data while converting to host byte order */
+               REVERSE32(*data++,W256[j]);
+               /* Apply the SHA-256 compression function to update a..h */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+               /* Apply the SHA-256 compression function to update a..h with copy */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+               T2 = Sigma0_256(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 16);
+
+       do {
+               /* Part of the message block expansion: */
+               s0 = W256[(j+1)&0x0f];
+               s0 = sigma0_256(s0);
+               s1 = W256[(j+14)&0x0f];
+               s1 = sigma1_256(s1);
+
+               /* Apply the SHA-256 compression function to update a..h */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
+                    (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+               T2 = Sigma0_256(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 64);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void
+isc_sha256_update(isc_sha256_t *context, const isc_uint8_t *data, size_t len) {
+       unsigned int    freespace, usedspace;
+
+       if (len == 0U) {
+               /* Calling with no data is valid - we do nothing */
+               return;
+       }
+
+       /* Sanity check: */
+       REQUIRE(context != (isc_sha256_t *)0 && data != (isc_uint8_t*)0);
+
+       usedspace = (unsigned int)((context->bitcount >> 3) %
+                                  ISC_SHA256_BLOCK_LENGTH);
+       if (usedspace > 0) {
+               /* Calculate how much free space is available in the buffer */
+               freespace = ISC_SHA256_BLOCK_LENGTH - usedspace;
+
+               if (len >= freespace) {
+                       /* Fill the buffer completely and process it */
+                       memcpy(&context->buffer[usedspace], data, freespace);
+                       context->bitcount += freespace << 3;
+                       len -= freespace;
+                       data += freespace;
+                       isc_sha256_transform(context,
+                                            (isc_uint32_t*)context->buffer);
+               } else {
+                       /* The buffer is not yet full */
+                       memcpy(&context->buffer[usedspace], data, len);
+                       context->bitcount += len << 3;
+                       /* Clean up: */
+                       usedspace = freespace = 0;
+                       return;
+               }
+       }
+       while (len >= ISC_SHA256_BLOCK_LENGTH) {
+               /* Process as many complete blocks as we can */
+               memcpy(context->buffer, data, ISC_SHA256_BLOCK_LENGTH);
+               isc_sha256_transform(context, (isc_uint32_t*)context->buffer);
+               context->bitcount += ISC_SHA256_BLOCK_LENGTH << 3;
+               len -= ISC_SHA256_BLOCK_LENGTH;
+               data += ISC_SHA256_BLOCK_LENGTH;
+       }
+       if (len > 0U) {
+               /* There's left-overs, so save 'em */
+               memcpy(context->buffer, data, len);
+               context->bitcount += len << 3;
+       }
+       /* Clean up: */
+       usedspace = freespace = 0;
+}
+
+void
+isc_sha256_final(isc_uint8_t digest[], isc_sha256_t *context) {
+       isc_uint32_t    *d = (isc_uint32_t*)digest;
+       unsigned int    usedspace;
+
+       /* Sanity check: */
+       REQUIRE(context != (isc_sha256_t *)0);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (isc_uint8_t*)0) {
+               usedspace = (unsigned int)((context->bitcount >> 3) %
+                                          ISC_SHA256_BLOCK_LENGTH);
+#if BYTE_ORDER == LITTLE_ENDIAN
+               /* Convert FROM host byte order */
+               REVERSE64(context->bitcount,context->bitcount);
+#endif
+               if (usedspace > 0) {
+                       /* Begin padding with a 1 bit: */
+                       context->buffer[usedspace++] = 0x80;
+
+                       if (usedspace <= ISC_SHA256_SHORT_BLOCK_LENGTH) {
+                               /* Set-up for the last transform: */
+                               memset(&context->buffer[usedspace], 0,
+                                      ISC_SHA256_SHORT_BLOCK_LENGTH - usedspace);
+                       } else {
+                               if (usedspace < ISC_SHA256_BLOCK_LENGTH) {
+                                       memset(&context->buffer[usedspace], 0,
+                                              ISC_SHA256_BLOCK_LENGTH -
+                                              usedspace);
+                               }
+                               /* Do second-to-last transform: */
+                               isc_sha256_transform(context,
+                                              (isc_uint32_t*)context->buffer);
+
+                               /* And set-up for the last transform: */
+                               memset(context->buffer, 0,
+                                      ISC_SHA256_SHORT_BLOCK_LENGTH);
+                       }
+               } else {
+                       /* Set-up for the last transform: */
+                       memset(context->buffer, 0, ISC_SHA256_SHORT_BLOCK_LENGTH);
+
+                       /* Begin padding with a 1 bit: */
+                       *context->buffer = 0x80;
+               }
+               /* Set the bit count: */
+               *(isc_uint64_t*)&context->buffer[ISC_SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
+
+               /* Final transform: */
+               isc_sha256_transform(context, (isc_uint32_t*)context->buffer);
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 8; j++) {
+                               REVERSE32(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               memcpy(d, context->state, ISC_SHA256_DIGESTLENGTH);
+#endif
+       }
+
+       /* Clean up state data: */
+       memset(context, 0, sizeof(context));
+       usedspace = 0;
+}
+
+char *
+isc_sha256_end(isc_sha256_t *context, char buffer[]) {
+       isc_uint8_t     digest[ISC_SHA256_DIGESTLENGTH], *d = digest;
+       unsigned int    i;
+
+       /* Sanity check: */
+       REQUIRE(context != (isc_sha256_t *)0);
+
+       if (buffer != (char*)0) {
+               isc_sha256_final(digest, context);
+
+               for (i = 0; i < ISC_SHA256_DIGESTLENGTH; i++) {
+                       *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+                       *buffer++ = sha2_hex_digits[*d & 0x0f];
+                       d++;
+               }
+               *buffer = (char)0;
+       } else {
+               memset(context, 0, sizeof(context));
+       }
+       memset(digest, 0, ISC_SHA256_DIGESTLENGTH);
+       return buffer;
+}
+
+char *
+isc_sha256_data(const isc_uint8_t* data, size_t len,
+               char digest[ISC_SHA256_DIGESTSTRINGLENGTH])
+{
+       isc_sha256_t context;
+
+       isc_sha256_init(&context);
+       isc_sha256_update(&context, data, len);
+       return (isc_sha256_end(&context, digest));
+}
+
+
+/*** SHA-512: *********************************************************/
+void
+isc_sha512_init(isc_sha512_t *context) {
+       if (context == (isc_sha512_t *)0) {
+               return;
+       }
+       memcpy(context->state, sha512_initial_hash_value,
+              ISC_SHA512_DIGESTLENGTH);
+       memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH);
+       context->bitcount[0] = context->bitcount[1] =  0;
+}
+
+#ifdef ISC_SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-512 round macros: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)      \
+       REVERSE64(*data++, W512[j]); \
+       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+            K512[j] + W512[j]; \
+       (d) += T1, \
+       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
+       j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)      \
+       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+            K512[j] + (W512[j] = *data++); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+       j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512(a,b,c,d,e,f,g,h)      \
+       s0 = W512[(j+1)&0x0f]; \
+       s0 = sigma0_512(s0); \
+       s1 = W512[(j+14)&0x0f]; \
+       s1 = sigma1_512(s1); \
+       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
+            (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+       j++
+
+void isc_sha512_transform(isc_sha512_t *context, const isc_uint64_t* data) {
+       isc_uint64_t    a, b, c, d, e, f, g, h, s0, s1;
+       isc_uint64_t    T1, *W512 = (isc_uint64_t*)context->buffer;
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+               ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
+               ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
+               ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
+               ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
+               ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
+               ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
+               ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
+               ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
+       } while (j < 16);
+
+       /* Now for the remaining rounds up to 79: */
+       do {
+               ROUND512(a,b,c,d,e,f,g,h);
+               ROUND512(h,a,b,c,d,e,f,g);
+               ROUND512(g,h,a,b,c,d,e,f);
+               ROUND512(f,g,h,a,b,c,d,e);
+               ROUND512(e,f,g,h,a,b,c,d);
+               ROUND512(d,e,f,g,h,a,b,c);
+               ROUND512(c,d,e,f,g,h,a,b);
+               ROUND512(b,c,d,e,f,g,h,a);
+       } while (j < 80);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void
+isc_sha512_transform(isc_sha512_t *context, const isc_uint64_t* data) {
+       isc_uint64_t    a, b, c, d, e, f, g, h, s0, s1;
+       isc_uint64_t    T1, T2, *W512 = (isc_uint64_t*)context->buffer;
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+               /* Convert TO host byte order */
+               REVERSE64(*data++, W512[j]);
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+               /* Apply the SHA-512 compression function to update a..h with copy */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 16);
+
+       do {
+               /* Part of the message block expansion: */
+               s0 = W512[(j+1)&0x0f];
+               s0 = sigma0_512(s0);
+               s1 = W512[(j+14)&0x0f];
+               s1 =  sigma1_512(s1);
+
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+                    (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 80);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* ISC_SHA2_UNROLL_TRANSFORM */
+
+void isc_sha512_update(isc_sha512_t *context, const isc_uint8_t *data, size_t len) {
+       unsigned int    freespace, usedspace;
+
+       if (len == 0U) {
+               /* Calling with no data is valid - we do nothing */
+               return;
+       }
+
+       /* Sanity check: */
+       REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0);
+
+       usedspace = (unsigned int)((context->bitcount[0] >> 3) %
+                                  ISC_SHA512_BLOCK_LENGTH);
+       if (usedspace > 0) {
+               /* Calculate how much free space is available in the buffer */
+               freespace = ISC_SHA512_BLOCK_LENGTH - usedspace;
+
+               if (len >= freespace) {
+                       /* Fill the buffer completely and process it */
+                       memcpy(&context->buffer[usedspace], data, freespace);
+                       ADDINC128(context->bitcount, freespace << 3);
+                       len -= freespace;
+                       data += freespace;
+                       isc_sha512_transform(context,
+                                            (isc_uint64_t*)context->buffer);
+               } else {
+                       /* The buffer is not yet full */
+                       memcpy(&context->buffer[usedspace], data, len);
+                       ADDINC128(context->bitcount, len << 3);
+                       /* Clean up: */
+                       usedspace = freespace = 0;
+                       return;
+               }
+       }
+       while (len >= ISC_SHA512_BLOCK_LENGTH) {
+               /* Process as many complete blocks as we can */
+               memcpy(context->buffer, data, ISC_SHA512_BLOCK_LENGTH);
+               isc_sha512_transform(context, (isc_uint64_t*)context->buffer);
+               ADDINC128(context->bitcount, ISC_SHA512_BLOCK_LENGTH << 3);
+               len -= ISC_SHA512_BLOCK_LENGTH;
+               data += ISC_SHA512_BLOCK_LENGTH;
+       }
+       if (len > 0U) {
+               /* There's left-overs, so save 'em */
+               memcpy(context->buffer, data, len);
+               ADDINC128(context->bitcount, len << 3);
+       }
+       /* Clean up: */
+       usedspace = freespace = 0;
+}
+
+void isc_sha512_last(isc_sha512_t *context) {
+       unsigned int    usedspace;
+
+       usedspace = (unsigned int)((context->bitcount[0] >> 3) %
+                                   ISC_SHA512_BLOCK_LENGTH);
+#if BYTE_ORDER == LITTLE_ENDIAN
+       /* Convert FROM host byte order */
+       REVERSE64(context->bitcount[0],context->bitcount[0]);
+       REVERSE64(context->bitcount[1],context->bitcount[1]);
+#endif
+       if (usedspace > 0) {
+               /* Begin padding with a 1 bit: */
+               context->buffer[usedspace++] = 0x80;
+
+               if (usedspace <= ISC_SHA512_SHORT_BLOCK_LENGTH) {
+                       /* Set-up for the last transform: */
+                       memset(&context->buffer[usedspace], 0,
+                              ISC_SHA512_SHORT_BLOCK_LENGTH - usedspace);
+               } else {
+                       if (usedspace < ISC_SHA512_BLOCK_LENGTH) {
+                               memset(&context->buffer[usedspace], 0,
+                                      ISC_SHA512_BLOCK_LENGTH - usedspace);
+                       }
+                       /* Do second-to-last transform: */
+                       isc_sha512_transform(context,
+                                           (isc_uint64_t*)context->buffer);
+
+                       /* And set-up for the last transform: */
+                       memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH - 2);
+               }
+       } else {
+               /* Prepare for final transform: */
+               memset(context->buffer, 0, ISC_SHA512_SHORT_BLOCK_LENGTH);
+
+               /* Begin padding with a 1 bit: */
+               *context->buffer = 0x80;
+       }
+       /* Store the length of input data (in bits): */
+       *(isc_uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
+       *(isc_uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
+
+       /* Final transform: */
+       isc_sha512_transform(context, (isc_uint64_t*)context->buffer);
+}
+
+void isc_sha512_final(isc_uint8_t digest[], isc_sha512_t *context) {
+       isc_uint64_t    *d = (isc_uint64_t*)digest;
+
+       /* Sanity check: */
+       REQUIRE(context != (isc_sha512_t *)0);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (isc_uint8_t*)0) {
+               isc_sha512_last(context);
+
+               /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 8; j++) {
+                               REVERSE64(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               memcpy(d, context->state, ISC_SHA512_DIGESTLENGTH);
+#endif
+       }
+
+       /* Zero out state data */
+       memset(context, 0, sizeof(context));
+}
+
+char *
+isc_sha512_end(isc_sha512_t *context, char buffer[]) {
+       isc_uint8_t     digest[ISC_SHA512_DIGESTLENGTH], *d = digest;
+       unsigned int    i;
+
+       /* Sanity check: */
+       REQUIRE(context != (isc_sha512_t *)0);
+
+       if (buffer != (char*)0) {
+               isc_sha512_final(digest, context);
+
+               for (i = 0; i < ISC_SHA512_DIGESTLENGTH; i++) {
+                       *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+                       *buffer++ = sha2_hex_digits[*d & 0x0f];
+                       d++;
+               }
+               *buffer = (char)0;
+       } else {
+               memset(context, 0, sizeof(context));
+       }
+       memset(digest, 0, ISC_SHA512_DIGESTLENGTH);
+       return buffer;
+}
+
+char *
+isc_sha512_data(const isc_uint8_t *data, size_t len,
+               char digest[ISC_SHA512_DIGESTSTRINGLENGTH])
+{
+       isc_sha512_t    context;
+
+       isc_sha512_init(&context);
+       isc_sha512_update(&context, data, len);
+       return (isc_sha512_end(&context, digest));
+}
+
+
+/*** SHA-384: *********************************************************/
+void
+isc_sha384_init(isc_sha384_t *context) {
+       if (context == (isc_sha384_t *)0) {
+               return;
+       }
+       memcpy(context->state, sha384_initial_hash_value,
+              ISC_SHA512_DIGESTLENGTH);
+       memset(context->buffer, 0, ISC_SHA384_BLOCK_LENGTH);
+       context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+void
+isc_sha384_update(isc_sha384_t *context, const isc_uint8_t* data, size_t len) {
+       isc_sha512_update((isc_sha512_t *)context, data, len);
+}
+
+void
+isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) {
+       isc_uint64_t    *d = (isc_uint64_t*)digest;
+
+       /* Sanity check: */
+       REQUIRE(context != (isc_sha384_t *)0);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (isc_uint8_t*)0) {
+               isc_sha512_last((isc_sha512_t *)context);
+
+               /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 6; j++) {
+                               REVERSE64(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               memcpy(d, context->state, ISC_SHA384_DIGESTLENGTH);
+#endif
+       }
+
+       /* Zero out state data */
+       memset(context, 0, sizeof(context));
+}
+
+char *
+isc_sha384_end(isc_sha384_t *context, char buffer[]) {
+       isc_uint8_t     digest[ISC_SHA384_DIGESTLENGTH], *d = digest;
+       unsigned int    i;
+
+       /* Sanity check: */
+       REQUIRE(context != (isc_sha384_t *)0);
+
+       if (buffer != (char*)0) {
+               isc_sha384_final(digest, context);
+
+               for (i = 0; i < ISC_SHA384_DIGESTLENGTH; i++) {
+                       *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+                       *buffer++ = sha2_hex_digits[*d & 0x0f];
+                       d++;
+               }
+               *buffer = (char)0;
+       } else {
+               memset(context, 0, sizeof(context));
+       }
+       memset(digest, 0, ISC_SHA384_DIGESTLENGTH);
+       return buffer;
+}
+
+char*
+isc_sha384_data(const isc_uint8_t *data, size_t len,
+               char digest[ISC_SHA384_DIGESTSTRINGLENGTH])
+{
+       isc_sha384_t context;
+
+       isc_sha384_init(&context);
+       isc_sha384_update(&context, data, len);
+       return (isc_sha384_end(&context, digest));
+}
index be8d6598864f10eca723757424805c77762f859c..62975df34ddf0ecf4979b679898abb5701f22bf9 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: sockaddr.c,v 1.48.2.1.2.10 2004/05/15 03:46:12 jinmei Exp $ */
+/* $Id: sockaddr.c,v 1.70 2007/06/19 23:47:17 tbox Exp $ */
 
-#include <config.h>
+/*! \file */
 
-#define ISC_ONLY_IPV6
+#include <config.h>
 
 #include <stdio.h>
 
 #include <isc/buffer.h>
-/*
- * We currently don't need hashing here
- */
-#if 0
 #include <isc/hash.h>
-#endif
-
 #include <isc/msgs.h>
 #include <isc/netaddr.h>
 #include <isc/print.h>
 
 isc_boolean_t
 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
+       return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
+                                          ISC_SOCKADDR_CMPPORT|
+                                          ISC_SOCKADDR_CMPSCOPE));
+}
+
+isc_boolean_t
+isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
+       return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
+                                          ISC_SOCKADDR_CMPSCOPE));
+}
+
+isc_boolean_t
+isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+                    unsigned int flags)
+{
        REQUIRE(a != NULL && b != NULL);
 
        if (a->length != b->length)
@@ -55,21 +64,33 @@ isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
                return (ISC_FALSE);
        switch (a->type.sa.sa_family) {
        case AF_INET:
-               if (memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
+               if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
+                   memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
                           sizeof(a->type.sin.sin_addr)) != 0)
                        return (ISC_FALSE);
-               if (a->type.sin.sin_port != b->type.sin.sin_port)
+               if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
+                   a->type.sin.sin_port != b->type.sin.sin_port)
                        return (ISC_FALSE);
                break;
        case AF_INET6:
-               if (memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
+               if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
+                   memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
                           sizeof(a->type.sin6.sin6_addr)) != 0)
                        return (ISC_FALSE);
 #ifdef ISC_PLATFORM_HAVESCOPEID
-               if (a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id)
+               /*
+                * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
+                * ISC_FALSE if one of the scopes in zero.
+                */
+               if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
+                   a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
+                   ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
+                     (a->type.sin6.sin6_scope_id != 0 &&
+                      b->type.sin6.sin6_scope_id != 0)))
                        return (ISC_FALSE);
 #endif
-               if (a->type.sin6.sin6_port != b->type.sin6.sin6_port)
+               if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
+                   a->type.sin6.sin6_port != b->type.sin6.sin6_port)
                        return (ISC_FALSE);
                break;
        default:
@@ -79,37 +100,6 @@ isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
        return (ISC_TRUE);
 }
 
-isc_boolean_t
-isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
-       REQUIRE(a != NULL && b != NULL);
-
-       if (a->length != b->length)
-               return (ISC_FALSE);
-
-       if (a->type.sa.sa_family != b->type.sa.sa_family)
-               return (ISC_FALSE);
-       switch (a->type.sa.sa_family) {
-       case AF_INET:
-               if (memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
-                          sizeof(a->type.sin.sin_addr)) != 0)
-                       return (ISC_FALSE);
-               break;
-       case AF_INET6:
-               if (memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
-                          sizeof(a->type.sin6.sin6_addr)) != 0)
-                       return (ISC_FALSE);
-#ifdef ISC_PLATFORM_HAVESCOPEID
-               if (a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id)
-                       return (ISC_FALSE);
-#endif
-               break;
-       default:
-               if (memcmp(&a->type, &b->type, a->length) != 0)
-                       return (ISC_FALSE);
-       }
-       return (ISC_TRUE);
-}
-
 isc_boolean_t
 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
                          unsigned int prefixlen)
@@ -142,6 +132,23 @@ isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
        case AF_INET6:
                snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
                break;
+#ifdef ISC_PLAFORM_HAVESYSUNH
+       case AF_UNIX:
+               plen = strlen(sockaddr->type.sunix.sun_path);
+               if (plen >= isc_buffer_availablelength(target))
+                       return (ISC_R_NOSPACE);
+
+               isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
+
+               /*
+                * Null terminate after used region.
+                */
+               isc_buffer_availableregion(target, &avail);
+               INSIST(avail.length >= 1);
+               avail.base[0] = '\0';
+
+               return (ISC_R_SUCCESS);
+#endif
        default:
                return (ISC_R_FAILURE);
        }
@@ -190,10 +197,6 @@ isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
        }
 }
 
-#if 0
-/*
- * We currently don't need hashing here
- */
 unsigned int
 isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
        unsigned int length = 0;
@@ -211,7 +214,6 @@ isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
                p = ntohs(sockaddr->type.sin.sin_port);
                length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
                break;
-#if ISC_PLATFORM_HAVEIPV6
        case AF_INET6:
                in6 = &sockaddr->type.sin6.sin6_addr;
                if (IN6_IS_ADDR_V4MAPPED(in6)) {
@@ -223,7 +225,6 @@ isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
                }
                p = ntohs(sockaddr->type.sin6.sin6_port);
                break;
-#endif
        default:
                UNEXPECTED_ERROR(__FILE__, __LINE__,
                                 isc_msgcat_get(isc_msgcat,
@@ -245,7 +246,6 @@ isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
 
        return (h);
 }
-#endif
 
 void
 isc_sockaddr_any(isc_sockaddr_t *sockaddr)
@@ -264,7 +264,6 @@ isc_sockaddr_any(isc_sockaddr_t *sockaddr)
 void
 isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
 {
-#ifdef ISC_PLATFORM_HAVEIPV6
        memset(sockaddr, 0, sizeof(*sockaddr));
        sockaddr->type.sin6.sin6_family = AF_INET6;
 #ifdef ISC_PLATFORM_HAVESALEN
@@ -274,7 +273,6 @@ isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
        sockaddr->type.sin6.sin6_port = 0;
        sockaddr->length = sizeof(sockaddr->type.sin6);
        ISC_LINK_INIT(sockaddr, link);
-#endif
 }
 
 void
@@ -371,7 +369,7 @@ isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
                    in_port_t port)
 {
        memset(sockaddr, 0, sizeof(*sockaddr));
-       sockaddr->type.sin.sin_family = (short)na->family;
+       sockaddr->type.sin.sin_family = na->family;
        switch (na->family) {
        case AF_INET:
                sockaddr->length = sizeof(sockaddr->type.sin);
@@ -417,7 +415,7 @@ isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
 }
 
 in_port_t
-isc_sockaddr_getport(isc_sockaddr_t *sockaddr) {
+isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
        in_port_t port = 0;
 
        switch (sockaddr->type.sa.sa_family) {
@@ -439,15 +437,19 @@ isc_sockaddr_getport(isc_sockaddr_t *sockaddr) {
 }
 
 isc_boolean_t
-isc_sockaddr_ismulticast(isc_sockaddr_t *sockaddr) {
+isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
        isc_netaddr_t netaddr;
 
-       isc_netaddr_fromsockaddr(&netaddr, sockaddr);
-       return (isc_netaddr_ismulticast(&netaddr));
+       if (sockaddr->type.sa.sa_family == AF_INET ||
+           sockaddr->type.sa.sa_family == AF_INET6) {
+               isc_netaddr_fromsockaddr(&netaddr, sockaddr);
+               return (isc_netaddr_ismulticast(&netaddr));
+       }
+       return (ISC_FALSE);
 }
 
 isc_boolean_t
-isc_sockaddr_isexperimental(isc_sockaddr_t *sockaddr) {
+isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
        isc_netaddr_t netaddr;
 
        if (sockaddr->type.sa.sa_family == AF_INET) {
@@ -458,7 +460,7 @@ isc_sockaddr_isexperimental(isc_sockaddr_t *sockaddr) {
 }
 
 isc_boolean_t
-isc_sockaddr_issitelocal(isc_sockaddr_t *sockaddr) {
+isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
        isc_netaddr_t netaddr;
 
        if (sockaddr->type.sa.sa_family == AF_INET6) {
@@ -469,7 +471,7 @@ isc_sockaddr_issitelocal(isc_sockaddr_t *sockaddr) {
 }
 
 isc_boolean_t
-isc_sockaddr_islinklocal(isc_sockaddr_t *sockaddr) {
+isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
        isc_netaddr_t netaddr;
 
        if (sockaddr->type.sa.sa_family == AF_INET6) {
@@ -478,3 +480,24 @@ isc_sockaddr_islinklocal(isc_sockaddr_t *sockaddr) {
        }
        return (ISC_FALSE);
 }
+
+isc_result_t
+isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
+#ifdef ISC_PLATFORM_HAVESYSUNH
+       if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
+               return (ISC_R_NOSPACE);
+       memset(sockaddr, 0, sizeof(*sockaddr));
+       sockaddr->length = sizeof(sockaddr->type.sunix);
+       sockaddr->type.sunix.sun_family = AF_UNIX;
+#ifdef ISC_PLATFORM_HAVESALEN
+       sockaddr->type.sunix.sun_len =
+                       (unsigned char)sizeof(sockaddr->type.sunix);
+#endif
+       strcpy(sockaddr->type.sunix.sun_path, path);
+       return (ISC_R_SUCCESS);
+#else
+       UNUSED(sockaddr);
+       UNUSED(path);
+       return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
diff --git a/lib/isc/sparc64/include/isc/atomic.h b/lib/isc/sparc64/include/isc/atomic.h
new file mode 100644 (file)
index 0000000..5533ddb
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.5 2007/06/19 23:47:18 tbox Exp $ */
+
+/*
+ * This code was written based on FreeBSD's kernel source whose copyright
+ * follows:
+ */
+
+/*-
+ * Copyright (c) 1998 Doug Rabson.
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     from: FreeBSD: src/sys/i386/include/atomic.h,v 1.20 2001/02/11
+ * $FreeBSD: src/sys/sparc64/include/atomic.h,v 1.8 2004/05/22 00:52:16 marius Exp $
+ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#define        ASI_P   0x80            /* Primary Address Space Identifier */
+
+#ifdef ISC_PLATFORM_USEGCCASM
+
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static inline isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+       isc_int32_t prev, swapped;
+
+       for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) {
+               swapped = prev + val;
+               __asm__ volatile(
+                       "casa [%1] %2, %3, %0"
+                       : "+r"(swapped)
+                       : "r"(p), "n"(ASI_P), "r"(prev));
+               if (swapped == prev)
+                       break;
+       }
+
+       return (prev);
+}
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static inline void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+       isc_int32_t prev, swapped;
+
+       for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) {
+               swapped = val;
+               __asm__ volatile(
+                       "casa [%1] %2, %3, %0"
+                       : "+r"(swapped)
+                       : "r"(p), "n"(ASI_P), "r"(prev)
+                       : "memory");
+               if (swapped == prev)
+                       break;
+       }
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'.  The original value is returned in any
+ * case.
+ */
+static inline isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+       isc_int32_t temp = val;
+
+       __asm__ volatile(
+               "casa [%1] %2, %3, %0"
+               : "+r"(temp)
+               : "r"(p), "n"(ASI_P), "r"(cmpval));
+
+       return (temp);
+}
+
+#else  /* ISC_PLATFORM_USEGCCASM */
+
+#error "unsupported compiler.  disable atomic ops by --disable-atomic"
+
+#endif /* ISC_PLATFORM_USEGCCASM */
+
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/stats.c b/lib/isc/stats.c
new file mode 100644 (file)
index 0000000..9e4e089
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stats.c,v 1.3.6.2 2009/01/29 23:47:44 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <isc/atomic.h>
+#include <isc/buffer.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/rwlock.h>
+#include <isc/stats.h>
+#include <isc/util.h>
+
+#define ISC_STATS_MAGIC                        ISC_MAGIC('S', 't', 'a', 't')
+#define ISC_STATS_VALID(x)             ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
+
+#ifndef ISC_STATS_USEMULTIFIELDS
+#if defined(ISC_RWLOCK_USEATOMIC) && defined(ISC_PLATFORM_HAVEXADD) && !defined(ISC_PLATFORM_HAVEXADDQ)
+#define ISC_STATS_USEMULTIFIELDS 1
+#else
+#define ISC_STATS_USEMULTIFIELDS 0
+#endif
+#endif /* ISC_STATS_USEMULTIFIELDS */
+
+#if ISC_STATS_USEMULTIFIELDS
+typedef struct {
+       isc_uint32_t hi;
+       isc_uint32_t lo;
+} isc_stat_t;
+#else
+typedef isc_uint64_t isc_stat_t;
+#endif
+
+struct isc_stats {
+       /*% Unlocked */
+       unsigned int    magic;
+       isc_mem_t       *mctx;
+       int             ncounters;
+
+       isc_mutex_t     lock;
+       unsigned int    references; /* locked by lock */
+
+       /*%
+        * Locked by counterlock or unlocked if efficient rwlock is not
+        * available.
+        */
+#ifdef ISC_RWLOCK_USEATOMIC
+       isc_rwlock_t    counterlock;
+#endif
+       isc_stat_t      *counters;
+
+       /*%
+        * We don't want to lock the counters while we are dumping, so we first
+        * copy the current counter values into a local array.  This buffer
+        * will be used as the copy destination.  It's allocated on creation
+        * of the stats structure so that the dump operation won't fail due
+        * to memory allocation failure.
+        * XXX: this approach is weird for non-threaded build because the
+        * additional memory and the copy overhead could be avoided.  We prefer
+        * simplicity here, however, under the assumption that this function
+        * should be only rarely called.
+        */
+       isc_uint64_t    *copiedcounters;
+};
+
+static isc_result_t
+create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) {
+       isc_stats_t *stats;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(statsp != NULL && *statsp == NULL);
+
+       stats = isc_mem_get(mctx, sizeof(*stats));
+       if (stats == NULL)
+               return (ISC_R_NOMEMORY);
+
+       result = isc_mutex_init(&stats->lock);
+       if (result != ISC_R_SUCCESS)
+               goto clean_stats;
+
+       stats->counters = isc_mem_get(mctx, sizeof(isc_stat_t) * ncounters);
+       if (stats->counters == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto clean_mutex;
+       }
+       stats->copiedcounters = isc_mem_get(mctx,
+                                           sizeof(isc_uint64_t) * ncounters);
+       if (stats->copiedcounters == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto clean_counters;
+       }
+
+#ifdef ISC_RWLOCK_USEATOMIC
+       result = isc_rwlock_init(&stats->counterlock, 0, 0);
+       if (result != ISC_R_SUCCESS)
+               goto clean_copiedcounters;
+#endif
+
+       stats->references = 1;
+       memset(stats->counters, 0, sizeof(isc_stat_t) * ncounters);
+       stats->mctx = NULL;
+       isc_mem_attach(mctx, &stats->mctx);
+       stats->ncounters = ncounters;
+       stats->magic = ISC_STATS_MAGIC;
+
+       *statsp = stats;
+
+       return (result);
+
+clean_counters:
+       isc_mem_put(mctx, stats->counters, sizeof(isc_stat_t) * ncounters);
+
+#ifdef ISC_RWLOCK_USEATOMIC
+clean_copiedcounters:
+       isc_mem_put(mctx, stats->copiedcounters,
+                   sizeof(isc_stat_t) * ncounters);
+#endif
+
+clean_mutex:
+       DESTROYLOCK(&stats->lock);
+
+clean_stats:
+       isc_mem_put(mctx, stats, sizeof(*stats));
+
+       return (result);
+}
+
+void
+isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp) {
+       REQUIRE(ISC_STATS_VALID(stats));
+       REQUIRE(statsp != NULL && *statsp == NULL);
+
+       LOCK(&stats->lock);
+       stats->references++;
+       UNLOCK(&stats->lock);
+
+       *statsp = stats;
+}
+
+void
+isc_stats_detach(isc_stats_t **statsp) {
+       isc_stats_t *stats;
+
+       REQUIRE(statsp != NULL && ISC_STATS_VALID(*statsp));
+
+       stats = *statsp;
+       *statsp = NULL;
+
+       LOCK(&stats->lock);
+       stats->references--;
+       UNLOCK(&stats->lock);
+
+       if (stats->references == 0) {
+               isc_mem_put(stats->mctx, stats->copiedcounters,
+                           sizeof(isc_stat_t) * stats->ncounters);
+               isc_mem_put(stats->mctx, stats->counters,
+                           sizeof(isc_stat_t) * stats->ncounters);
+               DESTROYLOCK(&stats->lock);
+#ifdef ISC_RWLOCK_USEATOMIC
+               isc_rwlock_destroy(&stats->counterlock);
+#endif
+               isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
+       }
+}
+
+int
+isc_stats_ncounters(isc_stats_t *stats) {
+       REQUIRE(ISC_STATS_VALID(stats));
+
+       return (stats->ncounters);
+}
+
+static inline void
+incrementcounter(isc_stats_t *stats, int counter) {
+       isc_int32_t prev;
+
+#ifdef ISC_RWLOCK_USEATOMIC
+       /*
+        * We use a "read" lock to prevent other threads from reading the
+        * counter while we "writing" a counter field.  The write access itself
+        * is protected by the atomic operation.
+        */
+       isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read);
+#endif
+
+#if ISC_STATS_USEMULTIFIELDS
+       prev = isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].lo, 1);
+       /*
+        * If the lower 32-bit field overflows, increment the higher field.
+        * Note that it's *theoretically* possible that the lower field
+        * overlaps again before the higher field is incremented.  It doesn't
+        * matter, however, because we don't read the value until
+        * isc_stats_copy() is called where the whole process is protected
+        * by the write (exclusive) lock.
+        */
+       if (prev == (isc_int32_t)0xffffffff)
+               isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].hi, 1);
+#elif defined(ISC_PLATFORM_HAVEXADDQ)
+       UNUSED(prev);
+       isc_atomic_xaddq((isc_int64_t *)&stats->counters[counter], 1);
+#else
+       UNUSED(prev);
+       stats->counters[counter]++;
+#endif
+
+#ifdef ISC_RWLOCK_USEATOMIC
+       isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read);
+#endif
+}
+
+static inline void
+decrementcounter(isc_stats_t *stats, int counter) {
+       isc_int32_t prev;
+
+#ifdef ISC_RWLOCK_USEATOMIC
+       isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read);
+#endif
+
+#if ISC_STATS_USEMULTIFIELDS
+       prev = isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].lo, -1);
+       if (prev == 0)
+               isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].hi,
+                               -1);
+#elif defined(ISC_PLATFORM_HAVEXADDQ)
+       UNUSED(prev);
+       isc_atomic_xaddq((isc_int64_t *)&stats->counters[counter], -1);
+#else
+       UNUSED(prev);
+       stats->counters[counter]--;
+#endif
+
+#ifdef ISC_RWLOCK_USEATOMIC
+       isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read);
+#endif
+}
+
+static void
+copy_counters(isc_stats_t *stats) {
+       int i;
+
+#ifdef ISC_RWLOCK_USEATOMIC
+       /*
+        * We use a "write" lock before "reading" the statistics counters as
+        * an exclusive lock.
+        */
+       isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_write);
+#endif
+
+#if ISC_STATS_USEMULTIFIELDS
+       for (i = 0; i < stats->ncounters; i++) {
+               stats->copiedcounters[i] =
+                               (isc_uint64_t)(stats->counters[i].hi) << 32 |
+                               stats->counters[i].lo;
+       }
+#else
+       UNUSED(i);
+       memcpy(stats->copiedcounters, stats->counters,
+              stats->ncounters * sizeof(isc_stat_t));
+#endif
+
+#ifdef ISC_RWLOCK_USEATOMIC
+       isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write);
+#endif
+}
+
+isc_result_t
+isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters) {
+       REQUIRE(statsp != NULL && *statsp == NULL);
+
+       return (create_stats(mctx, ncounters, statsp));
+}
+
+void
+isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter) {
+       REQUIRE(ISC_STATS_VALID(stats));
+       REQUIRE(counter < stats->ncounters);
+
+       incrementcounter(stats, (int)counter);
+}
+
+void
+isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter) {
+       REQUIRE(ISC_STATS_VALID(stats));
+       REQUIRE(counter < stats->ncounters);
+
+       decrementcounter(stats, (int)counter);
+}
+
+void
+isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn,
+              void *arg, unsigned int options)
+{
+       int i;
+
+       REQUIRE(ISC_STATS_VALID(stats));
+
+       copy_counters(stats);
+
+       for (i = 0; i < stats->ncounters; i++) {
+               if ((options & ISC_STATSDUMP_VERBOSE) == 0 &&
+                   stats->copiedcounters[i] == 0)
+                               continue;
+               dump_fn((isc_statscounter_t)i, stats->copiedcounters[i], arg);
+       }
+}
diff --git a/lib/isc/string.c b/lib/isc/string.c
new file mode 100644 (file)
index 0000000..b9c43e7
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: string.c,v 1.20 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+static char digits[] = "0123456789abcdefghijklmnoprstuvwxyz";
+
+isc_uint64_t
+isc_string_touint64(char *source, char **end, int base) {
+       isc_uint64_t tmp;
+       isc_uint64_t overflow;
+       char *s = source;
+       char *o;
+       char c;
+
+       if ((base < 0) || (base == 1) || (base > 36)) {
+               *end = source;
+               return (0);
+       }
+
+       while (*s != 0 && isascii(*s&0xff) && isspace(*s&0xff))
+               s++;
+       if (*s == '+' /* || *s == '-' */)
+               s++;
+       if (base == 0) {
+               if (*s == '0' && (*(s+1) == 'X' || *(s+1) == 'x')) {
+                       s += 2;
+                       base = 16;
+               } else if (*s == '0')
+                       base = 8;
+               else
+                       base = 10;
+       }
+       if (*s == 0) {
+               *end = source;
+               return (0);
+       }
+       overflow = ~0;
+       overflow /= base;
+       tmp = 0;
+
+       while ((c = *s) != 0) {
+               c = tolower(c&0xff);
+               /* end ? */
+               if ((o = strchr(digits, c)) == NULL) {
+                       *end = s;
+                       return (tmp);
+               }
+               /* end ? */
+               if ((o - digits) >= base) {
+                       *end = s;
+                       return (tmp);
+               }
+               /* overflow ? */
+               if (tmp > overflow) {
+                       *end = source;
+                       return (0);
+               }
+               tmp *= base;
+               /* overflow ? */
+               if ((tmp + (o - digits)) < tmp) {
+                       *end = source;
+                       return (0);
+               }
+               tmp += o - digits;
+               s++;
+       }
+       *end = s;
+       return (tmp);
+}
+
+isc_result_t
+isc_string_copy(char *target, size_t size, const char *source) {
+       REQUIRE(size > 0U);
+
+       if (strlcpy(target, source, size) >= size) {
+               memset(target, ISC_STRING_MAGIC, size);
+               return (ISC_R_NOSPACE);
+       }
+
+       ENSURE(strlen(target) < size);
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_string_copy_truncate(char *target, size_t size, const char *source) {
+       REQUIRE(size > 0U);
+
+       strlcpy(target, source, size);
+
+       ENSURE(strlen(target) < size);
+}
+
+isc_result_t
+isc_string_append(char *target, size_t size, const char *source) {
+       REQUIRE(size > 0U);
+       REQUIRE(strlen(target) < size);
+
+       if (strlcat(target, source, size) >= size) {
+               memset(target, ISC_STRING_MAGIC, size);
+               return (ISC_R_NOSPACE);
+       }
+
+       ENSURE(strlen(target) < size);
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_string_append_truncate(char *target, size_t size, const char *source) {
+       REQUIRE(size > 0U);
+       REQUIRE(strlen(target) < size);
+
+       strlcat(target, source, size);
+
+       ENSURE(strlen(target) < size);
+}
+
+isc_result_t
+isc_string_printf(char *target, size_t size, const char *format, ...) {
+       va_list args;
+       size_t n;
+
+       REQUIRE(size > 0U);
+
+       va_start(args, format);
+       n = vsnprintf(target, size, format, args);
+       va_end(args);
+
+       if (n >= size) {
+               memset(target, ISC_STRING_MAGIC, size);
+               return (ISC_R_NOSPACE);
+       }
+
+       ENSURE(strlen(target) < size);
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_string_printf_truncate(char *target, size_t size, const char *format, ...) {
+       va_list args;
+       size_t n;
+
+       REQUIRE(size > 0U);
+
+       va_start(args, format);
+       n = vsnprintf(target, size, format, args);
+       va_end(args);
+
+       ENSURE(strlen(target) < size);
+}
+
+char *
+isc_string_regiondup(isc_mem_t *mctx, const isc_region_t *source) {
+       char *target;
+
+       REQUIRE(mctx != NULL);
+       REQUIRE(source != NULL);
+
+       target = (char *) isc_mem_allocate(mctx, source->length + 1);
+       if (target != NULL) {
+               memcpy(source->base, target, source->length);
+               target[source->length] = '\0';
+       }
+
+       return (target);
+}
+
+char *
+isc_string_separate(char **stringp, const char *delim) {
+       char *string = *stringp;
+       char *s;
+       const char *d;
+       char sc, dc;
+
+       if (string == NULL)
+               return (NULL);
+
+       for (s = string; (sc = *s) != '\0'; s++)
+               for (d = delim; (dc = *d) != '\0'; d++)
+                       if (sc == dc) {
+                               *s++ = '\0';
+                               *stringp = s;
+                               return (string);
+                       }
+       *stringp = NULL;
+       return (string);
+}
+
+size_t
+isc_string_strlcpy(char *dst, const char *src, size_t size)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = size;
+
+       /* Copy as many bytes as will fit */
+       if (n != 0U && --n != 0U) {
+               do {
+                       if ((*d++ = *s++) == 0)
+                               break;
+               } while (--n != 0U);
+       }
+
+       /* Not enough room in dst, add NUL and traverse rest of src */
+       if (n == 0U) {
+               if (size != 0U)
+                       *d = '\0';              /* NUL-terminate dst */
+               while (*s++)
+                       ;
+       }
+
+       return(s - src - 1);    /* count does not include NUL */
+}
+
+size_t
+isc_string_strlcat(char *dst, const char *src, size_t size)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = size;
+       size_t dlen;
+
+       /* Find the end of dst and adjust bytes left but don't go past end */
+       while (n-- != 0U && *d != '\0')
+               d++;
+       dlen = d - dst;
+       n = size - dlen;
+
+       if (n == 0U)
+               return(dlen + strlen(s));
+       while (*s != '\0') {
+               if (n != 1U) {
+                       *d++ = *s;
+                       n--;
+               }
+               s++;
+       }
+       *d = '\0';
+
+       return(dlen + (s - src));       /* count does not include NUL */
+}
diff --git a/lib/isc/strtoul.c b/lib/isc/strtoul.c
new file mode 100644 (file)
index 0000000..18d93e2
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*! \file */
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoul.c  8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+/* $Id: strtoul.c,v 1.7 2007/06/19 23:47:17 tbox Exp $ */
+
+#include <config.h>
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <isc/stdlib.h>
+#include <isc/util.h>
+
+/*!
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+isc_strtoul(const char *nptr, char **endptr, int base) {
+       const char *s = nptr;
+       unsigned long acc;
+       unsigned char c;
+       unsigned long cutoff;
+       int neg = 0, any, cutlim;
+
+       /*
+        * See strtol for comments as to the logic used.
+        */
+       do {
+               c = *s++;
+       } while (isspace(c));
+       if (c == '-') {
+               neg = 1;
+               c = *s++;
+       } else if (c == '+')
+               c = *s++;
+       if ((base == 0 || base == 16) &&
+           c == '0' && (*s == 'x' || *s == 'X')) {
+               c = s[1];
+               s += 2;
+               base = 16;
+       }
+       if (base == 0)
+               base = c == '0' ? 8 : 10;
+       cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
+       cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
+       for (acc = 0, any = 0;; c = *s++) {
+               if (!isascii(c))
+                       break;
+               if (isdigit(c))
+                       c -= '0';
+               else if (isalpha(c))
+                       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+               else
+                       break;
+               if (c >= base)
+                       break;
+               if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+                       any = -1;
+               else {
+                       any = 1;
+                       acc *= base;
+                       acc += c;
+               }
+       }
+       if (any < 0) {
+               acc = ULONG_MAX;
+               errno = ERANGE;
+       } else if (neg)
+               acc = -acc;
+       if (endptr != 0)
+               DE_CONST(any ? s - 1 : nptr, *endptr);
+       return (acc);
+}
diff --git a/lib/isc/symtab.c b/lib/isc/symtab.c
new file mode 100644 (file)
index 0000000..9f8e798
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: symtab.c,v 1.30 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/string.h>
+#include <isc/symtab.h>
+#include <isc/util.h>
+
+typedef struct elt {
+       char *                          key;
+       unsigned int                    type;
+       isc_symvalue_t                  value;
+       LINK(struct elt)                link;
+} elt_t;
+
+typedef LIST(elt_t)                    eltlist_t;
+
+#define SYMTAB_MAGIC                   ISC_MAGIC('S', 'y', 'm', 'T')
+#define VALID_SYMTAB(st)               ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
+
+struct isc_symtab {
+       /* Unlocked. */
+       unsigned int                    magic;
+       isc_mem_t *                     mctx;
+       unsigned int                    size;
+       eltlist_t *                     table;
+       isc_symtabaction_t              undefine_action;
+       void *                          undefine_arg;
+       isc_boolean_t                   case_sensitive;
+};
+
+isc_result_t
+isc_symtab_create(isc_mem_t *mctx, unsigned int size,
+                 isc_symtabaction_t undefine_action,
+                 void *undefine_arg,
+                 isc_boolean_t case_sensitive,
+                 isc_symtab_t **symtabp)
+{
+       isc_symtab_t *symtab;
+       unsigned int i;
+
+       REQUIRE(mctx != NULL);
+       REQUIRE(symtabp != NULL && *symtabp == NULL);
+       REQUIRE(size > 0);      /* Should be prime. */
+
+       symtab = (isc_symtab_t *)isc_mem_get(mctx, sizeof(*symtab));
+       if (symtab == NULL)
+               return (ISC_R_NOMEMORY);
+       symtab->table = (eltlist_t *)isc_mem_get(mctx,
+                                                size * sizeof(eltlist_t));
+       if (symtab->table == NULL) {
+               isc_mem_put(mctx, symtab, sizeof(*symtab));
+               return (ISC_R_NOMEMORY);
+       }
+       for (i = 0; i < size; i++)
+               INIT_LIST(symtab->table[i]);
+       symtab->mctx = mctx;
+       symtab->size = size;
+       symtab->undefine_action = undefine_action;
+       symtab->undefine_arg = undefine_arg;
+       symtab->case_sensitive = case_sensitive;
+       symtab->magic = SYMTAB_MAGIC;
+
+       *symtabp = symtab;
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_symtab_destroy(isc_symtab_t **symtabp) {
+       isc_symtab_t *symtab;
+       unsigned int i;
+       elt_t *elt, *nelt;
+
+       REQUIRE(symtabp != NULL);
+       symtab = *symtabp;
+       REQUIRE(VALID_SYMTAB(symtab));
+
+       for (i = 0; i < symtab->size; i++) {
+               for (elt = HEAD(symtab->table[i]); elt != NULL; elt = nelt) {
+                       nelt = NEXT(elt, link);
+                       if (symtab->undefine_action != NULL)
+                              (symtab->undefine_action)(elt->key,
+                                                        elt->type,
+                                                        elt->value,
+                                                        symtab->undefine_arg);
+                       isc_mem_put(symtab->mctx, elt, sizeof(*elt));
+               }
+       }
+       isc_mem_put(symtab->mctx, symtab->table,
+                   symtab->size * sizeof(eltlist_t));
+       symtab->magic = 0;
+       isc_mem_put(symtab->mctx, symtab, sizeof(*symtab));
+
+       *symtabp = NULL;
+}
+
+static inline unsigned int
+hash(const char *key, isc_boolean_t case_sensitive) {
+       const char *s;
+       unsigned int h = 0;
+       int c;
+
+       /*
+        * This hash function is similar to the one Ousterhout
+        * uses in Tcl.
+        */
+
+       if (case_sensitive) {
+               for (s = key; *s != '\0'; s++) {
+                       h += (h << 3) + *s;
+               }
+       } else {
+               for (s = key; *s != '\0'; s++) {
+                       c = *s;
+                       c = tolower((unsigned char)c);
+                       h += (h << 3) + c;
+               }
+       }
+
+       return (h);
+}
+
+#define FIND(s, k, t, b, e) \
+       b = hash((k), (s)->case_sensitive) % (s)->size; \
+       if ((s)->case_sensitive) { \
+               for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \
+                       if (((t) == 0 || e->type == (t)) && \
+                           strcmp(e->key, (k)) == 0) \
+                               break; \
+               } \
+       } else { \
+               for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \
+                       if (((t) == 0 || e->type == (t)) && \
+                           strcasecmp(e->key, (k)) == 0) \
+                               break; \
+               } \
+       }
+
+isc_result_t
+isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
+                 isc_symvalue_t *value)
+{
+       unsigned int bucket;
+       elt_t *elt;
+
+       REQUIRE(VALID_SYMTAB(symtab));
+       REQUIRE(key != NULL);
+
+       FIND(symtab, key, type, bucket, elt);
+
+       if (elt == NULL)
+               return (ISC_R_NOTFOUND);
+
+       if (value != NULL)
+               *value = elt->value;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
+                 isc_symvalue_t value, isc_symexists_t exists_policy)
+{
+       unsigned int bucket;
+       elt_t *elt;
+
+       REQUIRE(VALID_SYMTAB(symtab));
+       REQUIRE(key != NULL);
+       REQUIRE(type != 0);
+
+       FIND(symtab, key, type, bucket, elt);
+
+       if (exists_policy != isc_symexists_add && elt != NULL) {
+               if (exists_policy == isc_symexists_reject)
+                       return (ISC_R_EXISTS);
+               INSIST(exists_policy == isc_symexists_replace);
+               UNLINK(symtab->table[bucket], elt, link);
+               if (symtab->undefine_action != NULL)
+                       (symtab->undefine_action)(elt->key, elt->type,
+                                                 elt->value,
+                                                 symtab->undefine_arg);
+       } else {
+               elt = (elt_t *)isc_mem_get(symtab->mctx, sizeof(*elt));
+               if (elt == NULL)
+                       return (ISC_R_NOMEMORY);
+               ISC_LINK_INIT(elt, link);
+       }
+
+       /*
+        * Though the "key" can be const coming in, it is not stored as const
+        * so that the calling program can easily have writable access to
+        * it in its undefine_action function.  In the event that it *was*
+        * truly const coming in and then the caller modified it anyway ...
+        * well, don't do that!
+        */
+       DE_CONST(key, elt->key);
+       elt->type = type;
+       elt->value = value;
+
+       /*
+        * We prepend so that the most recent definition will be found.
+        */
+       PREPEND(symtab->table[bucket], elt, link);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type) {
+       unsigned int bucket;
+       elt_t *elt;
+
+       REQUIRE(VALID_SYMTAB(symtab));
+       REQUIRE(key != NULL);
+
+       FIND(symtab, key, type, bucket, elt);
+
+       if (elt == NULL)
+               return (ISC_R_NOTFOUND);
+
+       if (symtab->undefine_action != NULL)
+               (symtab->undefine_action)(elt->key, elt->type,
+                                         elt->value, symtab->undefine_arg);
+       UNLINK(symtab->table[bucket], elt, link);
+       isc_mem_put(symtab->mctx, elt, sizeof(*elt));
+
+       return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/task.c b/lib/isc/task.c
new file mode 100644 (file)
index 0000000..a630173
--- /dev/null
@@ -0,0 +1,1376 @@
+/*
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: task.c,v 1.107 2008/03/27 23:46:57 tbox Exp $ */
+
+/*! \file
+ * \author Principal Author: Bob Halley
+ */
+
+/*
+ * XXXRTH  Need to document the states a task can be in, and the rules
+ * for changing states.
+ */
+
+#include <config.h>
+
+#include <isc/condition.h>
+#include <isc/event.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/platform.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+#include <isc/xml.h>
+
+#ifndef ISC_PLATFORM_USETHREADS
+#include "task_p.h"
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifdef ISC_TASK_TRACE
+#define XTRACE(m)              fprintf(stderr, "task %p thread %lu: %s\n", \
+                                      task, isc_thread_self(), (m))
+#define XTTRACE(t, m)          fprintf(stderr, "task %p thread %lu: %s\n", \
+                                      (t), isc_thread_self(), (m))
+#define XTHREADTRACE(m)                fprintf(stderr, "thread %lu: %s\n", \
+                                      isc_thread_self(), (m))
+#else
+#define XTRACE(m)
+#define XTTRACE(t, m)
+#define XTHREADTRACE(m)
+#endif
+
+/***
+ *** Types.
+ ***/
+
+typedef enum {
+       task_state_idle, task_state_ready, task_state_running,
+       task_state_done
+} task_state_t;
+
+#ifdef HAVE_LIBXML2
+static const char *statenames[] = {
+       "idle", "ready", "running", "done",
+};
+#endif
+
+#define TASK_MAGIC                     ISC_MAGIC('T', 'A', 'S', 'K')
+#define VALID_TASK(t)                  ISC_MAGIC_VALID(t, TASK_MAGIC)
+
+struct isc_task {
+       /* Not locked. */
+       unsigned int                    magic;
+       isc_taskmgr_t *                 manager;
+       isc_mutex_t                     lock;
+       /* Locked by task lock. */
+       task_state_t                    state;
+       unsigned int                    references;
+       isc_eventlist_t                 events;
+       isc_eventlist_t                 on_shutdown;
+       unsigned int                    quantum;
+       unsigned int                    flags;
+       isc_stdtime_t                   now;
+       char                            name[16];
+       void *                          tag;
+       /* Locked by task manager lock. */
+       LINK(isc_task_t)                link;
+       LINK(isc_task_t)                ready_link;
+};
+
+#define TASK_F_SHUTTINGDOWN            0x01
+
+#define TASK_SHUTTINGDOWN(t)           (((t)->flags & TASK_F_SHUTTINGDOWN) \
+                                        != 0)
+
+#define TASK_MANAGER_MAGIC             ISC_MAGIC('T', 'S', 'K', 'M')
+#define VALID_MANAGER(m)               ISC_MAGIC_VALID(m, TASK_MANAGER_MAGIC)
+
+struct isc_taskmgr {
+       /* Not locked. */
+       unsigned int                    magic;
+       isc_mem_t *                     mctx;
+       isc_mutex_t                     lock;
+#ifdef ISC_PLATFORM_USETHREADS
+       unsigned int                    workers;
+       isc_thread_t *                  threads;
+#endif /* ISC_PLATFORM_USETHREADS */
+       /* Locked by task manager lock. */
+       unsigned int                    default_quantum;
+       LIST(isc_task_t)                tasks;
+       isc_tasklist_t                  ready_tasks;
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_condition_t                 work_available;
+       isc_condition_t                 exclusive_granted;
+#endif /* ISC_PLATFORM_USETHREADS */
+       unsigned int                    tasks_running;
+       isc_boolean_t                   exclusive_requested;
+       isc_boolean_t                   exiting;
+#ifndef ISC_PLATFORM_USETHREADS
+       unsigned int                    refs;
+#endif /* ISC_PLATFORM_USETHREADS */
+};
+
+#define DEFAULT_TASKMGR_QUANTUM                10
+#define DEFAULT_DEFAULT_QUANTUM                5
+#define FINISHED(m)                    ((m)->exiting && EMPTY((m)->tasks))
+
+#ifndef ISC_PLATFORM_USETHREADS
+static isc_taskmgr_t *taskmgr = NULL;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/***
+ *** Tasks.
+ ***/
+
+static void
+task_finished(isc_task_t *task) {
+       isc_taskmgr_t *manager = task->manager;
+
+       REQUIRE(EMPTY(task->events));
+       REQUIRE(EMPTY(task->on_shutdown));
+       REQUIRE(task->references == 0);
+       REQUIRE(task->state == task_state_done);
+
+       XTRACE("task_finished");
+
+       LOCK(&manager->lock);
+       UNLINK(manager->tasks, task, link);
+#ifdef ISC_PLATFORM_USETHREADS
+       if (FINISHED(manager)) {
+               /*
+                * All tasks have completed and the
+                * task manager is exiting.  Wake up
+                * any idle worker threads so they
+                * can exit.
+                */
+               BROADCAST(&manager->work_available);
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+       UNLOCK(&manager->lock);
+
+       DESTROYLOCK(&task->lock);
+       task->magic = 0;
+       isc_mem_put(manager->mctx, task, sizeof(*task));
+}
+
+isc_result_t
+isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
+               isc_task_t **taskp)
+{
+       isc_task_t *task;
+       isc_boolean_t exiting;
+       isc_result_t result;
+
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(taskp != NULL && *taskp == NULL);
+
+       task = isc_mem_get(manager->mctx, sizeof(*task));
+       if (task == NULL)
+               return (ISC_R_NOMEMORY);
+       XTRACE("isc_task_create");
+       task->manager = manager;
+       result = isc_mutex_init(&task->lock);
+       if (result != ISC_R_SUCCESS) {
+               isc_mem_put(manager->mctx, task, sizeof(*task));
+               return (result);
+       }
+       task->state = task_state_idle;
+       task->references = 1;
+       INIT_LIST(task->events);
+       INIT_LIST(task->on_shutdown);
+       task->quantum = quantum;
+       task->flags = 0;
+       task->now = 0;
+       memset(task->name, 0, sizeof(task->name));
+       task->tag = NULL;
+       INIT_LINK(task, link);
+       INIT_LINK(task, ready_link);
+
+       exiting = ISC_FALSE;
+       LOCK(&manager->lock);
+       if (!manager->exiting) {
+               if (task->quantum == 0)
+                       task->quantum = manager->default_quantum;
+               APPEND(manager->tasks, task, link);
+       } else
+               exiting = ISC_TRUE;
+       UNLOCK(&manager->lock);
+
+       if (exiting) {
+               DESTROYLOCK(&task->lock);
+               isc_mem_put(manager->mctx, task, sizeof(*task));
+               return (ISC_R_SHUTTINGDOWN);
+       }
+
+       task->magic = TASK_MAGIC;
+       *taskp = task;
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_task_attach(isc_task_t *source, isc_task_t **targetp) {
+
+       /*
+        * Attach *targetp to source.
+        */
+
+       REQUIRE(VALID_TASK(source));
+       REQUIRE(targetp != NULL && *targetp == NULL);
+
+       XTTRACE(source, "isc_task_attach");
+
+       LOCK(&source->lock);
+       source->references++;
+       UNLOCK(&source->lock);
+
+       *targetp = source;
+}
+
+static inline isc_boolean_t
+task_shutdown(isc_task_t *task) {
+       isc_boolean_t was_idle = ISC_FALSE;
+       isc_event_t *event, *prev;
+
+       /*
+        * Caller must be holding the task's lock.
+        */
+
+       XTRACE("task_shutdown");
+
+       if (! TASK_SHUTTINGDOWN(task)) {
+               XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                     ISC_MSG_SHUTTINGDOWN, "shutting down"));
+               task->flags |= TASK_F_SHUTTINGDOWN;
+               if (task->state == task_state_idle) {
+                       INSIST(EMPTY(task->events));
+                       task->state = task_state_ready;
+                       was_idle = ISC_TRUE;
+               }
+               INSIST(task->state == task_state_ready ||
+                      task->state == task_state_running);
+               /*
+                * Note that we post shutdown events LIFO.
+                */
+               for (event = TAIL(task->on_shutdown);
+                    event != NULL;
+                    event = prev) {
+                       prev = PREV(event, ev_link);
+                       DEQUEUE(task->on_shutdown, event, ev_link);
+                       ENQUEUE(task->events, event, ev_link);
+               }
+       }
+
+       return (was_idle);
+}
+
+static inline void
+task_ready(isc_task_t *task) {
+       isc_taskmgr_t *manager = task->manager;
+
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(task->state == task_state_ready);
+
+       XTRACE("task_ready");
+
+       LOCK(&manager->lock);
+
+       ENQUEUE(manager->ready_tasks, task, ready_link);
+#ifdef ISC_PLATFORM_USETHREADS
+       SIGNAL(&manager->work_available);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       UNLOCK(&manager->lock);
+}
+
+static inline isc_boolean_t
+task_detach(isc_task_t *task) {
+
+       /*
+        * Caller must be holding the task lock.
+        */
+
+       REQUIRE(task->references > 0);
+
+       XTRACE("detach");
+
+       task->references--;
+       if (task->references == 0 && task->state == task_state_idle) {
+               INSIST(EMPTY(task->events));
+               /*
+                * There are no references to this task, and no
+                * pending events.  We could try to optimize and
+                * either initiate shutdown or clean up the task,
+                * depending on its state, but it's easier to just
+                * make the task ready and allow run() or the event
+                * loop to deal with shutting down and termination.
+                */
+               task->state = task_state_ready;
+               return (ISC_TRUE);
+       }
+
+       return (ISC_FALSE);
+}
+
+void
+isc_task_detach(isc_task_t **taskp) {
+       isc_task_t *task;
+       isc_boolean_t was_idle;
+
+       /*
+        * Detach *taskp from its task.
+        */
+
+       REQUIRE(taskp != NULL);
+       task = *taskp;
+       REQUIRE(VALID_TASK(task));
+
+       XTRACE("isc_task_detach");
+
+       LOCK(&task->lock);
+       was_idle = task_detach(task);
+       UNLOCK(&task->lock);
+
+       if (was_idle)
+               task_ready(task);
+
+       *taskp = NULL;
+}
+
+static inline isc_boolean_t
+task_send(isc_task_t *task, isc_event_t **eventp) {
+       isc_boolean_t was_idle = ISC_FALSE;
+       isc_event_t *event;
+
+       /*
+        * Caller must be holding the task lock.
+        */
+
+       REQUIRE(eventp != NULL);
+       event = *eventp;
+       REQUIRE(event != NULL);
+       REQUIRE(event->ev_type > 0);
+       REQUIRE(task->state != task_state_done);
+
+       XTRACE("task_send");
+
+       if (task->state == task_state_idle) {
+               was_idle = ISC_TRUE;
+               INSIST(EMPTY(task->events));
+               task->state = task_state_ready;
+       }
+       INSIST(task->state == task_state_ready ||
+              task->state == task_state_running);
+       ENQUEUE(task->events, event, ev_link);
+       *eventp = NULL;
+
+       return (was_idle);
+}
+
+void
+isc_task_send(isc_task_t *task, isc_event_t **eventp) {
+       isc_boolean_t was_idle;
+
+       /*
+        * Send '*event' to 'task'.
+        */
+
+       REQUIRE(VALID_TASK(task));
+
+       XTRACE("isc_task_send");
+
+       /*
+        * We're trying hard to hold locks for as short a time as possible.
+        * We're also trying to hold as few locks as possible.  This is why
+        * some processing is deferred until after the lock is released.
+        */
+       LOCK(&task->lock);
+       was_idle = task_send(task, eventp);
+       UNLOCK(&task->lock);
+
+       if (was_idle) {
+               /*
+                * We need to add this task to the ready queue.
+                *
+                * We've waited until now to do it because making a task
+                * ready requires locking the manager.  If we tried to do
+                * this while holding the task lock, we could deadlock.
+                *
+                * We've changed the state to ready, so no one else will
+                * be trying to add this task to the ready queue.  The
+                * only way to leave the ready state is by executing the
+                * task.  It thus doesn't matter if events are added,
+                * removed, or a shutdown is started in the interval
+                * between the time we released the task lock, and the time
+                * we add the task to the ready queue.
+                */
+               task_ready(task);
+       }
+}
+
+void
+isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
+       isc_boolean_t idle1, idle2;
+       isc_task_t *task;
+
+       /*
+        * Send '*event' to '*taskp' and then detach '*taskp' from its
+        * task.
+        */
+
+       REQUIRE(taskp != NULL);
+       task = *taskp;
+       REQUIRE(VALID_TASK(task));
+
+       XTRACE("isc_task_sendanddetach");
+
+       LOCK(&task->lock);
+       idle1 = task_send(task, eventp);
+       idle2 = task_detach(task);
+       UNLOCK(&task->lock);
+
+       /*
+        * If idle1, then idle2 shouldn't be true as well since we're holding
+        * the task lock, and thus the task cannot switch from ready back to
+        * idle.
+        */
+       INSIST(!(idle1 && idle2));
+
+       if (idle1 || idle2)
+               task_ready(task);
+
+       *taskp = NULL;
+}
+
+#define PURGE_OK(event)        (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE) == 0)
+
+static unsigned int
+dequeue_events(isc_task_t *task, void *sender, isc_eventtype_t first,
+              isc_eventtype_t last, void *tag,
+              isc_eventlist_t *events, isc_boolean_t purging)
+{
+       isc_event_t *event, *next_event;
+       unsigned int count = 0;
+
+       REQUIRE(VALID_TASK(task));
+       REQUIRE(last >= first);
+
+       XTRACE("dequeue_events");
+
+       /*
+        * Events matching 'sender', whose type is >= first and <= last, and
+        * whose tag is 'tag' will be dequeued.  If 'purging', matching events
+        * which are marked as unpurgable will not be dequeued.
+        *
+        * sender == NULL means "any sender", and tag == NULL means "any tag".
+        */
+
+       LOCK(&task->lock);
+
+       for (event = HEAD(task->events); event != NULL; event = next_event) {
+               next_event = NEXT(event, ev_link);
+               if (event->ev_type >= first && event->ev_type <= last &&
+                   (sender == NULL || event->ev_sender == sender) &&
+                   (tag == NULL || event->ev_tag == tag) &&
+                   (!purging || PURGE_OK(event))) {
+                       DEQUEUE(task->events, event, ev_link);
+                       ENQUEUE(*events, event, ev_link);
+                       count++;
+               }
+       }
+
+       UNLOCK(&task->lock);
+
+       return (count);
+}
+
+unsigned int
+isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
+                   isc_eventtype_t last, void *tag)
+{
+       unsigned int count;
+       isc_eventlist_t events;
+       isc_event_t *event, *next_event;
+
+       /*
+        * Purge events from a task's event queue.
+        */
+
+       XTRACE("isc_task_purgerange");
+
+       ISC_LIST_INIT(events);
+
+       count = dequeue_events(task, sender, first, last, tag, &events,
+                              ISC_TRUE);
+
+       for (event = HEAD(events); event != NULL; event = next_event) {
+               next_event = NEXT(event, ev_link);
+               isc_event_free(&event);
+       }
+
+       /*
+        * Note that purging never changes the state of the task.
+        */
+
+       return (count);
+}
+
+unsigned int
+isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type,
+              void *tag)
+{
+       /*
+        * Purge events from a task's event queue.
+        */
+
+       XTRACE("isc_task_purge");
+
+       return (isc_task_purgerange(task, sender, type, type, tag));
+}
+
+isc_boolean_t
+isc_task_purgeevent(isc_task_t *task, isc_event_t *event) {
+       isc_event_t *curr_event, *next_event;
+
+       /*
+        * Purge 'event' from a task's event queue.
+        *
+        * XXXRTH:  WARNING:  This method may be removed before beta.
+        */
+
+       REQUIRE(VALID_TASK(task));
+
+       /*
+        * If 'event' is on the task's event queue, it will be purged,
+        * unless it is marked as unpurgeable.  'event' does not have to be
+        * on the task's event queue; in fact, it can even be an invalid
+        * pointer.  Purging only occurs if the event is actually on the task's
+        * event queue.
+        *
+        * Purging never changes the state of the task.
+        */
+
+       LOCK(&task->lock);
+       for (curr_event = HEAD(task->events);
+            curr_event != NULL;
+            curr_event = next_event) {
+               next_event = NEXT(curr_event, ev_link);
+               if (curr_event == event && PURGE_OK(event)) {
+                       DEQUEUE(task->events, curr_event, ev_link);
+                       break;
+               }
+       }
+       UNLOCK(&task->lock);
+
+       if (curr_event == NULL)
+               return (ISC_FALSE);
+
+       isc_event_free(&curr_event);
+
+       return (ISC_TRUE);
+}
+
+unsigned int
+isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first,
+                    isc_eventtype_t last, void *tag,
+                    isc_eventlist_t *events)
+{
+       /*
+        * Remove events from a task's event queue.
+        */
+
+       XTRACE("isc_task_unsendrange");
+
+       return (dequeue_events(task, sender, first, last, tag, events,
+                              ISC_FALSE));
+}
+
+unsigned int
+isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type,
+               void *tag, isc_eventlist_t *events)
+{
+       /*
+        * Remove events from a task's event queue.
+        */
+
+       XTRACE("isc_task_unsend");
+
+       return (dequeue_events(task, sender, type, type, tag, events,
+                              ISC_FALSE));
+}
+
+isc_result_t
+isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       isc_boolean_t disallowed = ISC_FALSE;
+       isc_result_t result = ISC_R_SUCCESS;
+       isc_event_t *event;
+
+       /*
+        * Send a shutdown event with action 'action' and argument 'arg' when
+        * 'task' is shutdown.
+        */
+
+       REQUIRE(VALID_TASK(task));
+       REQUIRE(action != NULL);
+
+       event = isc_event_allocate(task->manager->mctx,
+                                  NULL,
+                                  ISC_TASKEVENT_SHUTDOWN,
+                                  action,
+                                  arg,
+                                  sizeof(*event));
+       if (event == NULL)
+               return (ISC_R_NOMEMORY);
+
+       LOCK(&task->lock);
+       if (TASK_SHUTTINGDOWN(task)) {
+               disallowed = ISC_TRUE;
+               result = ISC_R_SHUTTINGDOWN;
+       } else
+               ENQUEUE(task->on_shutdown, event, ev_link);
+       UNLOCK(&task->lock);
+
+       if (disallowed)
+               isc_mem_put(task->manager->mctx, event, sizeof(*event));
+
+       return (result);
+}
+
+void
+isc_task_shutdown(isc_task_t *task) {
+       isc_boolean_t was_idle;
+
+       /*
+        * Shutdown 'task'.
+        */
+
+       REQUIRE(VALID_TASK(task));
+
+       LOCK(&task->lock);
+       was_idle = task_shutdown(task);
+       UNLOCK(&task->lock);
+
+       if (was_idle)
+               task_ready(task);
+}
+
+void
+isc_task_destroy(isc_task_t **taskp) {
+
+       /*
+        * Destroy '*taskp'.
+        */
+
+       REQUIRE(taskp != NULL);
+
+       isc_task_shutdown(*taskp);
+       isc_task_detach(taskp);
+}
+
+void
+isc_task_setname(isc_task_t *task, const char *name, void *tag) {
+
+       /*
+        * Name 'task'.
+        */
+
+       REQUIRE(VALID_TASK(task));
+
+       LOCK(&task->lock);
+       memset(task->name, 0, sizeof(task->name));
+       strncpy(task->name, name, sizeof(task->name) - 1);
+       task->tag = tag;
+       UNLOCK(&task->lock);
+}
+
+const char *
+isc_task_getname(isc_task_t *task) {
+       return (task->name);
+}
+
+void *
+isc_task_gettag(isc_task_t *task) {
+       return (task->tag);
+}
+
+void
+isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t) {
+       REQUIRE(VALID_TASK(task));
+       REQUIRE(t != NULL);
+
+       LOCK(&task->lock);
+
+       *t = task->now;
+
+       UNLOCK(&task->lock);
+}
+
+/***
+ *** Task Manager.
+ ***/
+static void
+dispatch(isc_taskmgr_t *manager) {
+       isc_task_t *task;
+#ifndef ISC_PLATFORM_USETHREADS
+       unsigned int total_dispatch_count = 0;
+       isc_tasklist_t ready_tasks;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       REQUIRE(VALID_MANAGER(manager));
+
+       /*
+        * Again we're trying to hold the lock for as short a time as possible
+        * and to do as little locking and unlocking as possible.
+        *
+        * In both while loops, the appropriate lock must be held before the
+        * while body starts.  Code which acquired the lock at the top of
+        * the loop would be more readable, but would result in a lot of
+        * extra locking.  Compare:
+        *
+        * Straightforward:
+        *
+        *      LOCK();
+        *      ...
+        *      UNLOCK();
+        *      while (expression) {
+        *              LOCK();
+        *              ...
+        *              UNLOCK();
+        *
+        *              Unlocked part here...
+        *
+        *              LOCK();
+        *              ...
+        *              UNLOCK();
+        *      }
+        *
+        * Note how if the loop continues we unlock and then immediately lock.
+        * For N iterations of the loop, this code does 2N+1 locks and 2N+1
+        * unlocks.  Also note that the lock is not held when the while
+        * condition is tested, which may or may not be important, depending
+        * on the expression.
+        *
+        * As written:
+        *
+        *      LOCK();
+        *      while (expression) {
+        *              ...
+        *              UNLOCK();
+        *
+        *              Unlocked part here...
+        *
+        *              LOCK();
+        *              ...
+        *      }
+        *      UNLOCK();
+        *
+        * For N iterations of the loop, this code does N+1 locks and N+1
+        * unlocks.  The while expression is always protected by the lock.
+        */
+
+#ifndef ISC_PLATFORM_USETHREADS
+       ISC_LIST_INIT(ready_tasks);
+#endif
+       LOCK(&manager->lock);
+       while (!FINISHED(manager)) {
+#ifdef ISC_PLATFORM_USETHREADS
+               /*
+                * For reasons similar to those given in the comment in
+                * isc_task_send() above, it is safe for us to dequeue
+                * the task while only holding the manager lock, and then
+                * change the task to running state while only holding the
+                * task lock.
+                */
+               while ((EMPTY(manager->ready_tasks) ||
+                       manager->exclusive_requested) &&
+                       !FINISHED(manager))
+               {
+                       XTHREADTRACE(isc_msgcat_get(isc_msgcat,
+                                                   ISC_MSGSET_GENERAL,
+                                                   ISC_MSG_WAIT, "wait"));
+                       WAIT(&manager->work_available, &manager->lock);
+                       XTHREADTRACE(isc_msgcat_get(isc_msgcat,
+                                                   ISC_MSGSET_TASK,
+                                                   ISC_MSG_AWAKE, "awake"));
+               }
+#else /* ISC_PLATFORM_USETHREADS */
+               if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM ||
+                   EMPTY(manager->ready_tasks))
+                       break;
+#endif /* ISC_PLATFORM_USETHREADS */
+               XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK,
+                                           ISC_MSG_WORKING, "working"));
+
+               task = HEAD(manager->ready_tasks);
+               if (task != NULL) {
+                       unsigned int dispatch_count = 0;
+                       isc_boolean_t done = ISC_FALSE;
+                       isc_boolean_t requeue = ISC_FALSE;
+                       isc_boolean_t finished = ISC_FALSE;
+                       isc_event_t *event;
+
+                       INSIST(VALID_TASK(task));
+
+                       /*
+                        * Note we only unlock the manager lock if we actually
+                        * have a task to do.  We must reacquire the manager
+                        * lock before exiting the 'if (task != NULL)' block.
+                        */
+                       DEQUEUE(manager->ready_tasks, task, ready_link);
+                       manager->tasks_running++;
+                       UNLOCK(&manager->lock);
+
+                       LOCK(&task->lock);
+                       INSIST(task->state == task_state_ready);
+                       task->state = task_state_running;
+                       XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                             ISC_MSG_RUNNING, "running"));
+                       isc_stdtime_get(&task->now);
+                       do {
+                               if (!EMPTY(task->events)) {
+                                       event = HEAD(task->events);
+                                       DEQUEUE(task->events, event, ev_link);
+
+                                       /*
+                                        * Execute the event action.
+                                        */
+                                       XTRACE(isc_msgcat_get(isc_msgcat,
+                                                           ISC_MSGSET_TASK,
+                                                           ISC_MSG_EXECUTE,
+                                                           "execute action"));
+                                       if (event->ev_action != NULL) {
+                                               UNLOCK(&task->lock);
+                                               (event->ev_action)(task,event);
+                                               LOCK(&task->lock);
+                                       }
+                                       dispatch_count++;
+#ifndef ISC_PLATFORM_USETHREADS
+                                       total_dispatch_count++;
+#endif /* ISC_PLATFORM_USETHREADS */
+                               }
+
+                               if (task->references == 0 &&
+                                   EMPTY(task->events) &&
+                                   !TASK_SHUTTINGDOWN(task)) {
+                                       isc_boolean_t was_idle;
+
+                                       /*
+                                        * There are no references and no
+                                        * pending events for this task,
+                                        * which means it will not become
+                                        * runnable again via an external
+                                        * action (such as sending an event
+                                        * or detaching).
+                                        *
+                                        * We initiate shutdown to prevent
+                                        * it from becoming a zombie.
+                                        *
+                                        * We do this here instead of in
+                                        * the "if EMPTY(task->events)" block
+                                        * below because:
+                                        *
+                                        *      If we post no shutdown events,
+                                        *      we want the task to finish.
+                                        *
+                                        *      If we did post shutdown events,
+                                        *      will still want the task's
+                                        *      quantum to be applied.
+                                        */
+                                       was_idle = task_shutdown(task);
+                                       INSIST(!was_idle);
+                               }
+
+                               if (EMPTY(task->events)) {
+                                       /*
+                                        * Nothing else to do for this task
+                                        * right now.
+                                        */
+                                       XTRACE(isc_msgcat_get(isc_msgcat,
+                                                             ISC_MSGSET_TASK,
+                                                             ISC_MSG_EMPTY,
+                                                             "empty"));
+                                       if (task->references == 0 &&
+                                           TASK_SHUTTINGDOWN(task)) {
+                                               /*
+                                                * The task is done.
+                                                */
+                                               XTRACE(isc_msgcat_get(
+                                                              isc_msgcat,
+                                                              ISC_MSGSET_TASK,
+                                                              ISC_MSG_DONE,
+                                                              "done"));
+                                               finished = ISC_TRUE;
+                                               task->state = task_state_done;
+                                       } else
+                                               task->state = task_state_idle;
+                                       done = ISC_TRUE;
+                               } else if (dispatch_count >= task->quantum) {
+                                       /*
+                                        * Our quantum has expired, but
+                                        * there is more work to be done.
+                                        * We'll requeue it to the ready
+                                        * queue later.
+                                        *
+                                        * We don't check quantum until
+                                        * dispatching at least one event,
+                                        * so the minimum quantum is one.
+                                        */
+                                       XTRACE(isc_msgcat_get(isc_msgcat,
+                                                             ISC_MSGSET_TASK,
+                                                             ISC_MSG_QUANTUM,
+                                                             "quantum"));
+                                       task->state = task_state_ready;
+                                       requeue = ISC_TRUE;
+                                       done = ISC_TRUE;
+                               }
+                       } while (!done);
+                       UNLOCK(&task->lock);
+
+                       if (finished)
+                               task_finished(task);
+
+                       LOCK(&manager->lock);
+                       manager->tasks_running--;
+#ifdef ISC_PLATFORM_USETHREADS
+                       if (manager->exclusive_requested &&
+                           manager->tasks_running == 1) {
+                               SIGNAL(&manager->exclusive_granted);
+                       }
+#endif /* ISC_PLATFORM_USETHREADS */
+                       if (requeue) {
+                               /*
+                                * We know we're awake, so we don't have
+                                * to wakeup any sleeping threads if the
+                                * ready queue is empty before we requeue.
+                                *
+                                * A possible optimization if the queue is
+                                * empty is to 'goto' the 'if (task != NULL)'
+                                * block, avoiding the ENQUEUE of the task
+                                * and the subsequent immediate DEQUEUE
+                                * (since it is the only executable task).
+                                * We don't do this because then we'd be
+                                * skipping the exit_requested check.  The
+                                * cost of ENQUEUE is low anyway, especially
+                                * when you consider that we'd have to do
+                                * an extra EMPTY check to see if we could
+                                * do the optimization.  If the ready queue
+                                * were usually nonempty, the 'optimization'
+                                * might even hurt rather than help.
+                                */
+#ifdef ISC_PLATFORM_USETHREADS
+                               ENQUEUE(manager->ready_tasks, task,
+                                       ready_link);
+#else
+                               ENQUEUE(ready_tasks, task, ready_link);
+#endif
+                       }
+               }
+       }
+#ifndef ISC_PLATFORM_USETHREADS
+       ISC_LIST_APPENDLIST(manager->ready_tasks, ready_tasks, ready_link);
+#endif
+       UNLOCK(&manager->lock);
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+static isc_threadresult_t
+#ifdef _WIN32
+WINAPI
+#endif
+run(void *uap) {
+       isc_taskmgr_t *manager = uap;
+
+       XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                   ISC_MSG_STARTING, "starting"));
+
+       dispatch(manager);
+
+       XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                   ISC_MSG_EXITING, "exiting"));
+
+       return ((isc_threadresult_t)0);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+static void
+manager_free(isc_taskmgr_t *manager) {
+       isc_mem_t *mctx;
+
+#ifdef ISC_PLATFORM_USETHREADS
+       (void)isc_condition_destroy(&manager->exclusive_granted);
+       (void)isc_condition_destroy(&manager->work_available);
+       isc_mem_free(manager->mctx, manager->threads);
+#endif /* ISC_PLATFORM_USETHREADS */
+       DESTROYLOCK(&manager->lock);
+       manager->magic = 0;
+       mctx = manager->mctx;
+       isc_mem_put(mctx, manager, sizeof(*manager));
+       isc_mem_detach(&mctx);
+}
+
+isc_result_t
+isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
+                  unsigned int default_quantum, isc_taskmgr_t **managerp)
+{
+       isc_result_t result;
+       unsigned int i, started = 0;
+       isc_taskmgr_t *manager;
+
+       /*
+        * Create a new task manager.
+        */
+
+       REQUIRE(workers > 0);
+       REQUIRE(managerp != NULL && *managerp == NULL);
+
+#ifndef ISC_PLATFORM_USETHREADS
+       UNUSED(i);
+       UNUSED(started);
+       UNUSED(workers);
+
+       if (taskmgr != NULL) {
+               taskmgr->refs++;
+               *managerp = taskmgr;
+               return (ISC_R_SUCCESS);
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       manager = isc_mem_get(mctx, sizeof(*manager));
+       if (manager == NULL)
+               return (ISC_R_NOMEMORY);
+       manager->magic = TASK_MANAGER_MAGIC;
+       manager->mctx = NULL;
+       result = isc_mutex_init(&manager->lock);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup_mgr;
+
+#ifdef ISC_PLATFORM_USETHREADS
+       manager->workers = 0;
+       manager->threads = isc_mem_allocate(mctx,
+                                           workers * sizeof(isc_thread_t));
+       if (manager->threads == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto cleanup_lock;
+       }
+       if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_condition_init() %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               result = ISC_R_UNEXPECTED;
+               goto cleanup_threads;
+       }
+       if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_condition_init() %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               result = ISC_R_UNEXPECTED;
+               goto cleanup_workavailable;
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+       if (default_quantum == 0)
+               default_quantum = DEFAULT_DEFAULT_QUANTUM;
+       manager->default_quantum = default_quantum;
+       INIT_LIST(manager->tasks);
+       INIT_LIST(manager->ready_tasks);
+       manager->tasks_running = 0;
+       manager->exclusive_requested = ISC_FALSE;
+       manager->exiting = ISC_FALSE;
+
+       isc_mem_attach(mctx, &manager->mctx);
+
+#ifdef ISC_PLATFORM_USETHREADS
+       LOCK(&manager->lock);
+       /*
+        * Start workers.
+        */
+       for (i = 0; i < workers; i++) {
+               if (isc_thread_create(run, manager,
+                                     &manager->threads[manager->workers]) ==
+                   ISC_R_SUCCESS) {
+                       manager->workers++;
+                       started++;
+               }
+       }
+       UNLOCK(&manager->lock);
+
+       if (started == 0) {
+               manager_free(manager);
+               return (ISC_R_NOTHREADS);
+       }
+       isc_thread_setconcurrency(workers);
+#else /* ISC_PLATFORM_USETHREADS */
+       manager->refs = 1;
+       taskmgr = manager;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       *managerp = manager;
+
+       return (ISC_R_SUCCESS);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ cleanup_workavailable:
+       (void)isc_condition_destroy(&manager->work_available);
+ cleanup_threads:
+       isc_mem_free(mctx, manager->threads);
+ cleanup_lock:
+       DESTROYLOCK(&manager->lock);
+#endif
+ cleanup_mgr:
+       isc_mem_put(mctx, manager, sizeof(*manager));
+       return (result);
+}
+
+void
+isc_taskmgr_destroy(isc_taskmgr_t **managerp) {
+       isc_taskmgr_t *manager;
+       isc_task_t *task;
+       unsigned int i;
+
+       /*
+        * Destroy '*managerp'.
+        */
+
+       REQUIRE(managerp != NULL);
+       manager = *managerp;
+       REQUIRE(VALID_MANAGER(manager));
+
+#ifndef ISC_PLATFORM_USETHREADS
+       UNUSED(i);
+
+       if (manager->refs > 1) {
+               manager->refs--;
+               *managerp = NULL;
+               return;
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       XTHREADTRACE("isc_taskmgr_destroy");
+       /*
+        * Only one non-worker thread may ever call this routine.
+        * If a worker thread wants to initiate shutdown of the
+        * task manager, it should ask some non-worker thread to call
+        * isc_taskmgr_destroy(), e.g. by signalling a condition variable
+        * that the startup thread is sleeping on.
+        */
+
+       /*
+        * Unlike elsewhere, we're going to hold this lock a long time.
+        * We need to do so, because otherwise the list of tasks could
+        * change while we were traversing it.
+        *
+        * This is also the only function where we will hold both the
+        * task manager lock and a task lock at the same time.
+        */
+
+       LOCK(&manager->lock);
+
+       /*
+        * Make sure we only get called once.
+        */
+       INSIST(!manager->exiting);
+       manager->exiting = ISC_TRUE;
+
+       /*
+        * Post shutdown event(s) to every task (if they haven't already been
+        * posted).
+        */
+       for (task = HEAD(manager->tasks);
+            task != NULL;
+            task = NEXT(task, link)) {
+               LOCK(&task->lock);
+               if (task_shutdown(task))
+                       ENQUEUE(manager->ready_tasks, task, ready_link);
+               UNLOCK(&task->lock);
+       }
+#ifdef ISC_PLATFORM_USETHREADS
+       /*
+        * Wake up any sleeping workers.  This ensures we get work done if
+        * there's work left to do, and if there are already no tasks left
+        * it will cause the workers to see manager->exiting.
+        */
+       BROADCAST(&manager->work_available);
+       UNLOCK(&manager->lock);
+
+       /*
+        * Wait for all the worker threads to exit.
+        */
+       for (i = 0; i < manager->workers; i++)
+               (void)isc_thread_join(manager->threads[i], NULL);
+#else /* ISC_PLATFORM_USETHREADS */
+       /*
+        * Dispatch the shutdown events.
+        */
+       UNLOCK(&manager->lock);
+       while (isc__taskmgr_ready())
+               (void)isc__taskmgr_dispatch();
+       if (!ISC_LIST_EMPTY(manager->tasks))
+               isc_mem_printallactive(stderr);
+       INSIST(ISC_LIST_EMPTY(manager->tasks));
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       manager_free(manager);
+
+       *managerp = NULL;
+}
+
+#ifndef ISC_PLATFORM_USETHREADS
+isc_boolean_t
+isc__taskmgr_ready(void) {
+       if (taskmgr == NULL)
+               return (ISC_FALSE);
+       return (ISC_TF(!ISC_LIST_EMPTY(taskmgr->ready_tasks)));
+}
+
+isc_result_t
+isc__taskmgr_dispatch(void) {
+       isc_taskmgr_t *manager = taskmgr;
+
+       if (taskmgr == NULL)
+               return (ISC_R_NOTFOUND);
+
+       dispatch(manager);
+
+       return (ISC_R_SUCCESS);
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_task_beginexclusive(isc_task_t *task) {
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_taskmgr_t *manager = task->manager;
+       REQUIRE(task->state == task_state_running);
+       LOCK(&manager->lock);
+       if (manager->exclusive_requested) {
+               UNLOCK(&manager->lock);
+               return (ISC_R_LOCKBUSY);
+       }
+       manager->exclusive_requested = ISC_TRUE;
+       while (manager->tasks_running > 1) {
+               WAIT(&manager->exclusive_granted, &manager->lock);
+       }
+       UNLOCK(&manager->lock);
+#else
+       UNUSED(task);
+#endif
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_task_endexclusive(isc_task_t *task) {
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_taskmgr_t *manager = task->manager;
+       REQUIRE(task->state == task_state_running);
+       LOCK(&manager->lock);
+       REQUIRE(manager->exclusive_requested);
+       manager->exclusive_requested = ISC_FALSE;
+       BROADCAST(&manager->work_available);
+       UNLOCK(&manager->lock);
+#else
+       UNUSED(task);
+#endif
+}
+
+#ifdef HAVE_LIBXML2
+
+void
+isc_taskmgr_renderxml(isc_taskmgr_t *mgr, xmlTextWriterPtr writer)
+{
+       isc_task_t *task;
+
+       LOCK(&mgr->lock);
+
+       /*
+        * Write out the thread-model, and some details about each depending
+        * on which type is enabled.
+        */
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "thread-model");
+#ifdef ISC_PLATFORM_USETHREADS
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "type");
+       xmlTextWriterWriteString(writer, ISC_XMLCHAR "threaded");
+       xmlTextWriterEndElement(writer); /* type */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "worker-threads");
+       xmlTextWriterWriteFormatString(writer, "%d", mgr->workers);
+       xmlTextWriterEndElement(writer); /* worker-threads */
+#else /* ISC_PLATFORM_USETHREADS */
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "type");
+       xmlTextWriterWriteString(writer, ISC_XMLCHAR "non-threaded");
+       xmlTextWriterEndElement(writer); /* type */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
+       xmlTextWriterWriteFormatString(writer, "%d", mgr->refs);
+       xmlTextWriterEndElement(writer); /* references */
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "default-quantum");
+       xmlTextWriterWriteFormatString(writer, "%d", mgr->default_quantum);
+       xmlTextWriterEndElement(writer); /* default-quantum */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running");
+       xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_running);
+       xmlTextWriterEndElement(writer); /* tasks-running */
+
+       xmlTextWriterEndElement(writer); /* thread-model */
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks");
+       task = ISC_LIST_HEAD(mgr->tasks);
+       while (task != NULL) {
+               LOCK(&task->lock);
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "task");
+
+               if (task->name[0] != 0) {
+                       xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
+                       xmlTextWriterWriteFormatString(writer, "%s",
+                                                      task->name);
+                       xmlTextWriterEndElement(writer); /* name */
+               }
+
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
+               xmlTextWriterWriteFormatString(writer, "%d", task->references);
+               xmlTextWriterEndElement(writer); /* references */
+
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
+               xmlTextWriterWriteFormatString(writer, "%p", task);
+               xmlTextWriterEndElement(writer); /* id */
+
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "state");
+               xmlTextWriterWriteFormatString(writer, "%s",
+                                              statenames[task->state]);
+               xmlTextWriterEndElement(writer); /* state */
+
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "quantum");
+               xmlTextWriterWriteFormatString(writer, "%d", task->quantum);
+               xmlTextWriterEndElement(writer); /* quantum */
+
+               xmlTextWriterEndElement(writer);
+
+               UNLOCK(&task->lock);
+               task = ISC_LIST_NEXT(task, link);
+       }
+       xmlTextWriterEndElement(writer); /* tasks */
+
+       UNLOCK(&mgr->lock);
+}
+#endif /* HAVE_LIBXML2 */
diff --git a/lib/isc/task_p.h b/lib/isc/task_p.h
new file mode 100644 (file)
index 0000000..c888103
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: task_p.h,v 1.11 2007/06/19 23:47:17 tbox Exp $ */
+
+#ifndef ISC_TASK_P_H
+#define ISC_TASK_P_H
+
+/*! \file */
+
+isc_boolean_t
+isc__taskmgr_ready(void);
+
+isc_result_t
+isc__taskmgr_dispatch(void);
+
+#endif /* ISC_TASK_P_H */
diff --git a/lib/isc/taskpool.c b/lib/isc/taskpool.c
new file mode 100644 (file)
index 0000000..d9c2fbe
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: taskpool.c,v 1.18 2007/06/18 23:47:44 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/taskpool.h>
+#include <isc/util.h>
+
+/***
+ *** Types.
+ ***/
+
+struct isc_taskpool {
+       isc_mem_t *                     mctx;
+       unsigned int                    ntasks;
+       isc_task_t **                   tasks;
+};
+/***
+ *** Functions.
+ ***/
+
+isc_result_t
+isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx,
+                   unsigned int ntasks, unsigned int quantum,
+                   isc_taskpool_t **poolp)
+{
+       unsigned int i;
+       isc_taskpool_t *pool;
+       isc_result_t result;
+
+       INSIST(ntasks > 0);
+       pool = isc_mem_get(mctx, sizeof(*pool));
+       if (pool == NULL)
+               return (ISC_R_NOMEMORY);
+       pool->mctx = mctx;
+       pool->ntasks = ntasks;
+       pool->tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
+       if (pool->tasks == NULL) {
+               isc_mem_put(mctx, pool, sizeof(*pool));
+               return (ISC_R_NOMEMORY);
+       }
+       for (i = 0; i < ntasks; i++)
+               pool->tasks[i] = NULL;
+       for (i = 0; i < ntasks; i++) {
+               result = isc_task_create(tmgr, quantum, &pool->tasks[i]);
+               if (result != ISC_R_SUCCESS) {
+                       isc_taskpool_destroy(&pool);
+                       return (result);
+               }
+               isc_task_setname(pool->tasks[i], "taskpool", NULL);
+       }
+       *poolp = pool;
+       return (ISC_R_SUCCESS);
+}
+
+void isc_taskpool_gettask(isc_taskpool_t *pool, unsigned int hash,
+                         isc_task_t **targetp)
+{
+       isc_task_attach(pool->tasks[hash % pool->ntasks], targetp);
+}
+
+void
+isc_taskpool_destroy(isc_taskpool_t **poolp) {
+       unsigned int i;
+       isc_taskpool_t *pool = *poolp;
+       for (i = 0; i < pool->ntasks; i++) {
+               if (pool->tasks[i] != NULL) {
+                       isc_task_detach(&pool->tasks[i]);
+               }
+       }
+       isc_mem_put(pool->mctx, pool->tasks,
+                   pool->ntasks * sizeof(isc_task_t *));
+       isc_mem_put(pool->mctx, pool, sizeof(*pool));
+       *poolp = NULL;
+}
+
+
diff --git a/lib/isc/timer.c b/lib/isc/timer.c
new file mode 100644 (file)
index 0000000..21fcd69
--- /dev/null
@@ -0,0 +1,933 @@
+/*
+ * Copyright (C) 2004, 2005, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: timer.c,v 1.84.58.4 2009/01/23 23:47:21 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/condition.h>
+#include <isc/heap.h>
+#include <isc/log.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/platform.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#ifndef ISC_PLATFORM_USETHREADS
+#include "timer_p.h"
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifdef ISC_TIMER_TRACE
+#define XTRACE(s)                      fprintf(stderr, "%s\n", (s))
+#define XTRACEID(s, t)                 fprintf(stderr, "%s %p\n", (s), (t))
+#define XTRACETIME(s, d)               fprintf(stderr, "%s %u.%09u\n", (s), \
+                                              (d).seconds, (d).nanoseconds)
+#define XTRACETIME2(s, d, n)           fprintf(stderr, "%s %u.%09u %u.%09u\n", (s), \
+                                              (d).seconds, (d).nanoseconds, (n).seconds, (n).nanoseconds)
+#define XTRACETIMER(s, t, d)           fprintf(stderr, "%s %p %u.%09u\n", (s), (t), \
+                                              (d).seconds, (d).nanoseconds)
+#else
+#define XTRACE(s)
+#define XTRACEID(s, t)
+#define XTRACETIME(s, d)
+#define XTRACETIME2(s, d, n)
+#define XTRACETIMER(s, t, d)
+#endif /* ISC_TIMER_TRACE */
+
+#define TIMER_MAGIC                    ISC_MAGIC('T', 'I', 'M', 'R')
+#define VALID_TIMER(t)                 ISC_MAGIC_VALID(t, TIMER_MAGIC)
+
+struct isc_timer {
+       /*! Not locked. */
+       unsigned int                    magic;
+       isc_timermgr_t *                manager;
+       isc_mutex_t                     lock;
+       /*! Locked by timer lock. */
+       unsigned int                    references;
+       isc_time_t                      idle;
+       /*! Locked by manager lock. */
+       isc_timertype_t                 type;
+       isc_time_t                      expires;
+       isc_interval_t                  interval;
+       isc_task_t *                    task;
+       isc_taskaction_t                action;
+       void *                          arg;
+       unsigned int                    index;
+       isc_time_t                      due;
+       LINK(isc_timer_t)               link;
+};
+
+#define TIMER_MANAGER_MAGIC            ISC_MAGIC('T', 'I', 'M', 'M')
+#define VALID_MANAGER(m)               ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC)
+
+struct isc_timermgr {
+       /* Not locked. */
+       unsigned int                    magic;
+       isc_mem_t *                     mctx;
+       isc_mutex_t                     lock;
+       /* Locked by manager lock. */
+       isc_boolean_t                   done;
+       LIST(isc_timer_t)               timers;
+       unsigned int                    nscheduled;
+       isc_time_t                      due;
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_condition_t                 wakeup;
+       isc_thread_t                    thread;
+#else /* ISC_PLATFORM_USETHREADS */
+       unsigned int                    refs;
+#endif /* ISC_PLATFORM_USETHREADS */
+       isc_heap_t *                    heap;
+};
+
+#ifndef ISC_PLATFORM_USETHREADS
+/*!
+ * If threads are not in use, there can be only one.
+ */
+static isc_timermgr_t *timermgr = NULL;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+static inline isc_result_t
+schedule(isc_timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) {
+       isc_result_t result;
+       isc_timermgr_t *manager;
+       isc_time_t due;
+       int cmp;
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_boolean_t timedwait;
+#endif
+
+       /*!
+        * Note: the caller must ensure locking.
+        */
+
+       REQUIRE(timer->type != isc_timertype_inactive);
+
+#ifndef ISC_PLATFORM_USETHREADS
+       UNUSED(signal_ok);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       manager = timer->manager;
+
+#ifdef ISC_PLATFORM_USETHREADS
+       /*!
+        * If the manager was timed wait, we may need to signal the
+        * manager to force a wakeup.
+        */
+       timedwait = ISC_TF(manager->nscheduled > 0 &&
+                          isc_time_seconds(&manager->due) != 0);
+#endif
+
+       /*
+        * Compute the new due time.
+        */
+       if (timer->type != isc_timertype_once) {
+               result = isc_time_add(now, &timer->interval, &due);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+               if (timer->type == isc_timertype_limited &&
+                   isc_time_compare(&timer->expires, &due) < 0)
+                       due = timer->expires;
+       } else {
+               if (isc_time_isepoch(&timer->idle))
+                       due = timer->expires;
+               else if (isc_time_isepoch(&timer->expires))
+                       due = timer->idle;
+               else if (isc_time_compare(&timer->idle, &timer->expires) < 0)
+                       due = timer->idle;
+               else
+                       due = timer->expires;
+       }
+
+       /*
+        * Schedule the timer.
+        */
+
+       if (timer->index > 0) {
+               /*
+                * Already scheduled.
+                */
+               cmp = isc_time_compare(&due, &timer->due);
+               timer->due = due;
+               switch (cmp) {
+               case -1:
+                       isc_heap_increased(manager->heap, timer->index);
+                       break;
+               case 1:
+                       isc_heap_decreased(manager->heap, timer->index);
+                       break;
+               case 0:
+                       /* Nothing to do. */
+                       break;
+               }
+       } else {
+               timer->due = due;
+               result = isc_heap_insert(manager->heap, timer);
+               if (result != ISC_R_SUCCESS) {
+                       INSIST(result == ISC_R_NOMEMORY);
+                       return (ISC_R_NOMEMORY);
+               }
+               manager->nscheduled++;
+       }
+
+       XTRACETIMER(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+                                  ISC_MSG_SCHEDULE, "schedule"), timer, due);
+
+       /*
+        * If this timer is at the head of the queue, we need to ensure
+        * that we won't miss it if it has a more recent due time than
+        * the current "next" timer.  We do this either by waking up the
+        * run thread, or explicitly setting the value in the manager.
+        */
+#ifdef ISC_PLATFORM_USETHREADS
+
+       /*
+        * This is a temporary (probably) hack to fix a bug on tru64 5.1
+        * and 5.1a.  Sometimes, pthread_cond_timedwait() doesn't actually
+        * return when the time expires, so here, we check to see if
+        * we're 15 seconds or more behind, and if we are, we signal
+        * the dispatcher.  This isn't such a bad idea as a general purpose
+        * watchdog, so perhaps we should just leave it in here.
+        */
+       if (signal_ok && timedwait) {
+               isc_interval_t fifteen;
+               isc_time_t then;
+
+               isc_interval_set(&fifteen, 15, 0);
+               result = isc_time_add(&manager->due, &fifteen, &then);
+
+               if (result == ISC_R_SUCCESS &&
+                   isc_time_compare(&then, now) < 0) {
+                       SIGNAL(&manager->wakeup);
+                       signal_ok = ISC_FALSE;
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_TIMER, ISC_LOG_WARNING,
+                                     "*** POKED TIMER ***");
+               }
+       }
+
+       if (timer->index == 1 && signal_ok) {
+               XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+                                     ISC_MSG_SIGNALSCHED,
+                                     "signal (schedule)"));
+               SIGNAL(&manager->wakeup);
+       }
+#else /* ISC_PLATFORM_USETHREADS */
+       if (timer->index == 1 &&
+           isc_time_compare(&timer->due, &manager->due) < 0)
+               manager->due = timer->due;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       return (ISC_R_SUCCESS);
+}
+
+static inline void
+deschedule(isc_timer_t *timer) {
+       isc_boolean_t need_wakeup = ISC_FALSE;
+       isc_timermgr_t *manager;
+
+       /*
+        * The caller must ensure locking.
+        */
+
+       manager = timer->manager;
+       if (timer->index > 0) {
+               if (timer->index == 1)
+                       need_wakeup = ISC_TRUE;
+               isc_heap_delete(manager->heap, timer->index);
+               timer->index = 0;
+               INSIST(manager->nscheduled > 0);
+               manager->nscheduled--;
+#ifdef ISC_PLATFORM_USETHREADS
+               if (need_wakeup) {
+                       XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+                                             ISC_MSG_SIGNALDESCHED,
+                                             "signal (deschedule)"));
+                       SIGNAL(&manager->wakeup);
+               }
+#endif /* ISC_PLATFORM_USETHREADS */
+       }
+}
+
+static void
+destroy(isc_timer_t *timer) {
+       isc_timermgr_t *manager = timer->manager;
+
+       /*
+        * The caller must ensure it is safe to destroy the timer.
+        */
+
+       LOCK(&manager->lock);
+
+       (void)isc_task_purgerange(timer->task,
+                                 timer,
+                                 ISC_TIMEREVENT_FIRSTEVENT,
+                                 ISC_TIMEREVENT_LASTEVENT,
+                                 NULL);
+       deschedule(timer);
+       UNLINK(manager->timers, timer, link);
+
+       UNLOCK(&manager->lock);
+
+       isc_task_detach(&timer->task);
+       DESTROYLOCK(&timer->lock);
+       timer->magic = 0;
+       isc_mem_put(manager->mctx, timer, sizeof(*timer));
+}
+
+isc_result_t
+isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type,
+                isc_time_t *expires, isc_interval_t *interval,
+                isc_task_t *task, isc_taskaction_t action, const void *arg,
+                isc_timer_t **timerp)
+{
+       isc_timer_t *timer;
+       isc_result_t result;
+       isc_time_t now;
+
+       /*
+        * Create a new 'type' timer managed by 'manager'.  The timers
+        * parameters are specified by 'expires' and 'interval'.  Events
+        * will be posted to 'task' and when dispatched 'action' will be
+        * called with 'arg' as the arg value.  The new timer is returned
+        * in 'timerp'.
+        */
+
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(task != NULL);
+       REQUIRE(action != NULL);
+       if (expires == NULL)
+               expires = isc_time_epoch;
+       if (interval == NULL)
+               interval = isc_interval_zero;
+       REQUIRE(type == isc_timertype_inactive ||
+               !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
+       REQUIRE(timerp != NULL && *timerp == NULL);
+       REQUIRE(type != isc_timertype_limited ||
+               !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
+
+       /*
+        * Get current time.
+        */
+       if (type != isc_timertype_inactive) {
+               TIME_NOW(&now);
+       } else {
+               /*
+                * We don't have to do this, but it keeps the compiler from
+                * complaining about "now" possibly being used without being
+                * set, even though it will never actually happen.
+                */
+               isc_time_settoepoch(&now);
+       }
+
+
+       timer = isc_mem_get(manager->mctx, sizeof(*timer));
+       if (timer == NULL)
+               return (ISC_R_NOMEMORY);
+
+       timer->manager = manager;
+       timer->references = 1;
+
+       if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
+               result = isc_time_add(&now, interval, &timer->idle);
+               if (result != ISC_R_SUCCESS) {
+                       isc_mem_put(manager->mctx, timer, sizeof(*timer));
+                       return (result);
+               }
+       } else
+               isc_time_settoepoch(&timer->idle);
+
+       timer->type = type;
+       timer->expires = *expires;
+       timer->interval = *interval;
+       timer->task = NULL;
+       isc_task_attach(task, &timer->task);
+       timer->action = action;
+       /*
+        * Removing the const attribute from "arg" is the best of two
+        * evils here.  If the timer->arg member is made const, then
+        * it affects a great many recipients of the timer event
+        * which did not pass in an "arg" that was truly const.
+        * Changing isc_timer_create() to not have "arg" prototyped as const,
+        * though, can cause compilers warnings for calls that *do*
+        * have a truly const arg.  The caller will have to carefully
+        * keep track of whether arg started as a true const.
+        */
+       DE_CONST(arg, timer->arg);
+       timer->index = 0;
+       result = isc_mutex_init(&timer->lock);
+       if (result != ISC_R_SUCCESS) {
+               isc_task_detach(&timer->task);
+               isc_mem_put(manager->mctx, timer, sizeof(*timer));
+               return (result);
+       }
+       ISC_LINK_INIT(timer, link);
+       timer->magic = TIMER_MAGIC;
+
+       LOCK(&manager->lock);
+
+       /*
+        * Note we don't have to lock the timer like we normally would because
+        * there are no external references to it yet.
+        */
+
+       if (type != isc_timertype_inactive)
+               result = schedule(timer, &now, ISC_TRUE);
+       else
+               result = ISC_R_SUCCESS;
+       if (result == ISC_R_SUCCESS)
+               APPEND(manager->timers, timer, link);
+
+       UNLOCK(&manager->lock);
+
+       if (result != ISC_R_SUCCESS) {
+               timer->magic = 0;
+               DESTROYLOCK(&timer->lock);
+               isc_task_detach(&timer->task);
+               isc_mem_put(manager->mctx, timer, sizeof(*timer));
+               return (result);
+       }
+
+       *timerp = timer;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
+               isc_time_t *expires, isc_interval_t *interval,
+               isc_boolean_t purge)
+{
+       isc_time_t now;
+       isc_timermgr_t *manager;
+       isc_result_t result;
+
+       /*
+        * Change the timer's type, expires, and interval values to the given
+        * values.  If 'purge' is ISC_TRUE, any pending events from this timer
+        * are purged from its task's event queue.
+        */
+
+       REQUIRE(VALID_TIMER(timer));
+       manager = timer->manager;
+       REQUIRE(VALID_MANAGER(manager));
+       if (expires == NULL)
+               expires = isc_time_epoch;
+       if (interval == NULL)
+               interval = isc_interval_zero;
+       REQUIRE(type == isc_timertype_inactive ||
+               !(isc_time_isepoch(expires) && isc_interval_iszero(interval)));
+       REQUIRE(type != isc_timertype_limited ||
+               !(isc_time_isepoch(expires) || isc_interval_iszero(interval)));
+
+       /*
+        * Get current time.
+        */
+       if (type != isc_timertype_inactive) {
+               TIME_NOW(&now);
+       } else {
+               /*
+                * We don't have to do this, but it keeps the compiler from
+                * complaining about "now" possibly being used without being
+                * set, even though it will never actually happen.
+                */
+               isc_time_settoepoch(&now);
+       }
+
+       manager = timer->manager;
+
+       LOCK(&manager->lock);
+       LOCK(&timer->lock);
+
+       if (purge)
+               (void)isc_task_purgerange(timer->task,
+                                         timer,
+                                         ISC_TIMEREVENT_FIRSTEVENT,
+                                         ISC_TIMEREVENT_LASTEVENT,
+                                         NULL);
+       timer->type = type;
+       timer->expires = *expires;
+       timer->interval = *interval;
+       if (type == isc_timertype_once && !isc_interval_iszero(interval)) {
+               result = isc_time_add(&now, interval, &timer->idle);
+       } else {
+               isc_time_settoepoch(&timer->idle);
+               result = ISC_R_SUCCESS;
+       }
+
+       if (result == ISC_R_SUCCESS) {
+               if (type == isc_timertype_inactive) {
+                       deschedule(timer);
+                       result = ISC_R_SUCCESS;
+               } else
+                       result = schedule(timer, &now, ISC_TRUE);
+       }
+
+       UNLOCK(&timer->lock);
+       UNLOCK(&manager->lock);
+
+       return (result);
+}
+
+isc_timertype_t
+isc_timer_gettype(isc_timer_t *timer) {
+       isc_timertype_t t;
+
+       REQUIRE(VALID_TIMER(timer));
+
+       LOCK(&timer->lock);
+       t = timer->type;
+       UNLOCK(&timer->lock);
+
+       return (t);
+}
+
+isc_result_t
+isc_timer_touch(isc_timer_t *timer) {
+       isc_result_t result;
+       isc_time_t now;
+
+       /*
+        * Set the last-touched time of 'timer' to the current time.
+        */
+
+       REQUIRE(VALID_TIMER(timer));
+
+       LOCK(&timer->lock);
+
+       /*
+        * We'd like to
+        *
+        *      REQUIRE(timer->type == isc_timertype_once);
+        *
+        * but we cannot without locking the manager lock too, which we
+        * don't want to do.
+        */
+
+       TIME_NOW(&now);
+       result = isc_time_add(&now, &timer->interval, &timer->idle);
+
+       UNLOCK(&timer->lock);
+
+       return (result);
+}
+
+void
+isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) {
+       /*
+        * Attach *timerp to timer.
+        */
+
+       REQUIRE(VALID_TIMER(timer));
+       REQUIRE(timerp != NULL && *timerp == NULL);
+
+       LOCK(&timer->lock);
+       timer->references++;
+       UNLOCK(&timer->lock);
+
+       *timerp = timer;
+}
+
+void
+isc_timer_detach(isc_timer_t **timerp) {
+       isc_timer_t *timer;
+       isc_boolean_t free_timer = ISC_FALSE;
+
+       /*
+        * Detach *timerp from its timer.
+        */
+
+       REQUIRE(timerp != NULL);
+       timer = *timerp;
+       REQUIRE(VALID_TIMER(timer));
+
+       LOCK(&timer->lock);
+       REQUIRE(timer->references > 0);
+       timer->references--;
+       if (timer->references == 0)
+               free_timer = ISC_TRUE;
+       UNLOCK(&timer->lock);
+
+       if (free_timer)
+               destroy(timer);
+
+       *timerp = NULL;
+}
+
+static void
+dispatch(isc_timermgr_t *manager, isc_time_t *now) {
+       isc_boolean_t done = ISC_FALSE, post_event, need_schedule;
+       isc_timerevent_t *event;
+       isc_eventtype_t type = 0;
+       isc_timer_t *timer;
+       isc_result_t result;
+       isc_boolean_t idle;
+
+       /*!
+        * The caller must be holding the manager lock.
+        */
+
+       while (manager->nscheduled > 0 && !done) {
+               timer = isc_heap_element(manager->heap, 1);
+               INSIST(timer->type != isc_timertype_inactive);
+               if (isc_time_compare(now, &timer->due) >= 0) {
+                       if (timer->type == isc_timertype_ticker) {
+                               type = ISC_TIMEREVENT_TICK;
+                               post_event = ISC_TRUE;
+                               need_schedule = ISC_TRUE;
+                       } else if (timer->type == isc_timertype_limited) {
+                               int cmp;
+                               cmp = isc_time_compare(now, &timer->expires);
+                               if (cmp >= 0) {
+                                       type = ISC_TIMEREVENT_LIFE;
+                                       post_event = ISC_TRUE;
+                                       need_schedule = ISC_FALSE;
+                               } else {
+                                       type = ISC_TIMEREVENT_TICK;
+                                       post_event = ISC_TRUE;
+                                       need_schedule = ISC_TRUE;
+                               }
+                       } else if (!isc_time_isepoch(&timer->expires) &&
+                                  isc_time_compare(now,
+                                                   &timer->expires) >= 0) {
+                               type = ISC_TIMEREVENT_LIFE;
+                               post_event = ISC_TRUE;
+                               need_schedule = ISC_FALSE;
+                       } else {
+                               idle = ISC_FALSE;
+
+                               LOCK(&timer->lock);
+                               if (!isc_time_isepoch(&timer->idle) &&
+                                   isc_time_compare(now,
+                                                    &timer->idle) >= 0) {
+                                       idle = ISC_TRUE;
+                               }
+                               UNLOCK(&timer->lock);
+                               if (idle) {
+                                       type = ISC_TIMEREVENT_IDLE;
+                                       post_event = ISC_TRUE;
+                                       need_schedule = ISC_FALSE;
+                               } else {
+                                       /*
+                                        * Idle timer has been touched;
+                                        * reschedule.
+                                        */
+                                       XTRACEID(isc_msgcat_get(isc_msgcat,
+                                                               ISC_MSGSET_TIMER,
+                                                               ISC_MSG_IDLERESCHED,
+                                                               "idle reschedule"),
+                                                timer);
+                                       post_event = ISC_FALSE;
+                                       need_schedule = ISC_TRUE;
+                               }
+                       }
+
+                       if (post_event) {
+                               XTRACEID(isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_TIMER,
+                                                       ISC_MSG_POSTING,
+                                                       "posting"), timer);
+                               /*
+                                * XXX We could preallocate this event.
+                                */
+                               event = (isc_timerevent_t *)isc_event_allocate(manager->mctx,
+                                                          timer,
+                                                          type,
+                                                          timer->action,
+                                                          timer->arg,
+                                                          sizeof(*event));
+
+                               if (event != NULL) {
+                                       event->due = timer->due;
+                                       isc_task_send(timer->task,
+                                                     ISC_EVENT_PTR(&event));
+                               } else
+                                       UNEXPECTED_ERROR(__FILE__, __LINE__, "%s",
+                                                isc_msgcat_get(isc_msgcat,
+                                                        ISC_MSGSET_TIMER,
+                                                        ISC_MSG_EVENTNOTALLOC,
+                                                        "couldn't "
+                                                        "allocate event"));
+                       }
+
+                       timer->index = 0;
+                       isc_heap_delete(manager->heap, 1);
+                       manager->nscheduled--;
+
+                       if (need_schedule) {
+                               result = schedule(timer, now, ISC_FALSE);
+                               if (result != ISC_R_SUCCESS)
+                                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                                        "%s: %u",
+                                               isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_TIMER,
+                                                       ISC_MSG_SCHEDFAIL,
+                                                       "couldn't schedule "
+                                                       "timer"),
+                                                        result);
+                       }
+               } else {
+                       manager->due = timer->due;
+                       done = ISC_TRUE;
+               }
+       }
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+static isc_threadresult_t
+#ifdef _WIN32                  /* XXXDCL */
+WINAPI
+#endif
+run(void *uap) {
+       isc_timermgr_t *manager = uap;
+       isc_time_t now;
+       isc_result_t result;
+
+       LOCK(&manager->lock);
+       while (!manager->done) {
+               TIME_NOW(&now);
+
+               XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                         ISC_MSG_RUNNING,
+                                         "running"), now);
+
+               dispatch(manager, &now);
+
+               if (manager->nscheduled > 0) {
+                       XTRACETIME2(isc_msgcat_get(isc_msgcat,
+                                                  ISC_MSGSET_GENERAL,
+                                                  ISC_MSG_WAITUNTIL,
+                                                  "waituntil"),
+                                   manager->due, now);
+                       result = WAITUNTIL(&manager->wakeup, &manager->lock, &manager->due);
+                       INSIST(result == ISC_R_SUCCESS ||
+                              result == ISC_R_TIMEDOUT);
+               } else {
+                       XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                                 ISC_MSG_WAIT, "wait"), now);
+                       WAIT(&manager->wakeup, &manager->lock);
+               }
+               XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+                                     ISC_MSG_WAKEUP, "wakeup"));
+       }
+       UNLOCK(&manager->lock);
+
+       return ((isc_threadresult_t)0);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+static isc_boolean_t
+sooner(void *v1, void *v2) {
+       isc_timer_t *t1, *t2;
+
+       t1 = v1;
+       t2 = v2;
+       REQUIRE(VALID_TIMER(t1));
+       REQUIRE(VALID_TIMER(t2));
+
+       if (isc_time_compare(&t1->due, &t2->due) < 0)
+               return (ISC_TRUE);
+       return (ISC_FALSE);
+}
+
+static void
+set_index(void *what, unsigned int index) {
+       isc_timer_t *timer;
+
+       timer = what;
+       REQUIRE(VALID_TIMER(timer));
+
+       timer->index = index;
+}
+
+isc_result_t
+isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) {
+       isc_timermgr_t *manager;
+       isc_result_t result;
+
+       /*
+        * Create a timer manager.
+        */
+
+       REQUIRE(managerp != NULL && *managerp == NULL);
+
+#ifndef ISC_PLATFORM_USETHREADS
+       if (timermgr != NULL) {
+               timermgr->refs++;
+               *managerp = timermgr;
+               return (ISC_R_SUCCESS);
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       manager = isc_mem_get(mctx, sizeof(*manager));
+       if (manager == NULL)
+               return (ISC_R_NOMEMORY);
+
+       manager->magic = TIMER_MANAGER_MAGIC;
+       manager->mctx = NULL;
+       manager->done = ISC_FALSE;
+       INIT_LIST(manager->timers);
+       manager->nscheduled = 0;
+       isc_time_settoepoch(&manager->due);
+       manager->heap = NULL;
+       result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap);
+       if (result != ISC_R_SUCCESS) {
+               INSIST(result == ISC_R_NOMEMORY);
+               isc_mem_put(mctx, manager, sizeof(*manager));
+               return (ISC_R_NOMEMORY);
+       }
+       result = isc_mutex_init(&manager->lock);
+       if (result != ISC_R_SUCCESS) {
+               isc_heap_destroy(&manager->heap);
+               isc_mem_put(mctx, manager, sizeof(*manager));
+               return (result);
+       }
+       isc_mem_attach(mctx, &manager->mctx);
+#ifdef ISC_PLATFORM_USETHREADS
+       if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) {
+               isc_mem_detach(&manager->mctx);
+               DESTROYLOCK(&manager->lock);
+               isc_heap_destroy(&manager->heap);
+               isc_mem_put(mctx, manager, sizeof(*manager));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_condition_init() %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               return (ISC_R_UNEXPECTED);
+       }
+       if (isc_thread_create(run, manager, &manager->thread) !=
+           ISC_R_SUCCESS) {
+               isc_mem_detach(&manager->mctx);
+               (void)isc_condition_destroy(&manager->wakeup);
+               DESTROYLOCK(&manager->lock);
+               isc_heap_destroy(&manager->heap);
+               isc_mem_put(mctx, manager, sizeof(*manager));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_thread_create() %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               return (ISC_R_UNEXPECTED);
+       }
+#else /* ISC_PLATFORM_USETHREADS */
+       manager->refs = 1;
+       timermgr = manager;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       *managerp = manager;
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_timermgr_poke(isc_timermgr_t *manager) {
+#ifdef ISC_PLATFORM_USETHREADS
+       REQUIRE(VALID_MANAGER(manager));
+
+       SIGNAL(&manager->wakeup);
+#else
+       UNUSED(manager);
+#endif
+}
+
+void
+isc_timermgr_destroy(isc_timermgr_t **managerp) {
+       isc_timermgr_t *manager;
+       isc_mem_t *mctx;
+
+       /*
+        * Destroy a timer manager.
+        */
+
+       REQUIRE(managerp != NULL);
+       manager = *managerp;
+       REQUIRE(VALID_MANAGER(manager));
+
+       LOCK(&manager->lock);
+
+#ifndef ISC_PLATFORM_USETHREADS
+       if (manager->refs > 1) {
+               manager->refs--;
+               UNLOCK(&manager->lock);
+               *managerp = NULL;
+               return;
+       }
+
+       isc__timermgr_dispatch();
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       REQUIRE(EMPTY(manager->timers));
+       manager->done = ISC_TRUE;
+
+#ifdef ISC_PLATFORM_USETHREADS
+       XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER,
+                             ISC_MSG_SIGNALDESTROY, "signal (destroy)"));
+       SIGNAL(&manager->wakeup);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       UNLOCK(&manager->lock);
+
+#ifdef ISC_PLATFORM_USETHREADS
+       /*
+        * Wait for thread to exit.
+        */
+       if (isc_thread_join(manager->thread, NULL) != ISC_R_SUCCESS)
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_thread_join() %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       /*
+        * Clean up.
+        */
+#ifdef ISC_PLATFORM_USETHREADS
+       (void)isc_condition_destroy(&manager->wakeup);
+#endif /* ISC_PLATFORM_USETHREADS */
+       DESTROYLOCK(&manager->lock);
+       isc_heap_destroy(&manager->heap);
+       manager->magic = 0;
+       mctx = manager->mctx;
+       isc_mem_put(mctx, manager, sizeof(*manager));
+       isc_mem_detach(&mctx);
+
+       *managerp = NULL;
+}
+
+#ifndef ISC_PLATFORM_USETHREADS
+isc_result_t
+isc__timermgr_nextevent(isc_time_t *when) {
+       if (timermgr == NULL || timermgr->nscheduled == 0)
+               return (ISC_R_NOTFOUND);
+       *when = timermgr->due;
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc__timermgr_dispatch(void) {
+       isc_time_t now;
+       if (timermgr == NULL)
+               return;
+       TIME_NOW(&now);
+       dispatch(timermgr, &now);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
diff --git a/lib/isc/timer_p.h b/lib/isc/timer_p.h
new file mode 100644 (file)
index 0000000..ec8e2e0
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: timer_p.h,v 1.10 2007/06/19 23:47:17 tbox Exp $ */
+
+#ifndef ISC_TIMER_P_H
+#define ISC_TIMER_P_H
+
+/*! \file */
+
+isc_result_t
+isc__timermgr_nextevent(isc_time_t *when);
+
+void
+isc__timermgr_dispatch(void);
+
+#endif /* ISC_TIMER_P_H */
diff --git a/lib/isc/unix/app.c b/lib/isc/unix/app.c
new file mode 100644 (file)
index 0000000..660b438
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: app.c,v 1.60 2008/10/15 03:41:17 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/time.h>
+#ifdef HAVE_EPOLL
+#include <sys/epoll.h>
+#endif
+
+#include <isc/app.h>
+#include <isc/boolean.h>
+#include <isc/condition.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/event.h>
+#include <isc/platform.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#ifdef ISC_PLATFORM_USETHREADS
+#include <pthread.h>
+#else /* ISC_PLATFORM_USETHREADS */
+#include "../timer_p.h"
+#include "../task_p.h"
+#include "socket_p.h"
+#endif /* ISC_PLATFORM_USETHREADS */
+
+static isc_eventlist_t         on_run;
+static isc_mutex_t             lock;
+static isc_boolean_t           shutdown_requested = ISC_FALSE;
+static isc_boolean_t           running = ISC_FALSE;
+/*!
+ * We assume that 'want_shutdown' can be read and written atomically.
+ */
+static volatile isc_boolean_t  want_shutdown = ISC_FALSE;
+/*
+ * We assume that 'want_reload' can be read and written atomically.
+ */
+static volatile isc_boolean_t  want_reload = ISC_FALSE;
+
+static isc_boolean_t           blocked  = ISC_FALSE;
+#ifdef ISC_PLATFORM_USETHREADS
+static pthread_t               blockedthread;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifdef HAVE_LINUXTHREADS
+/*!
+ * Linux has sigwait(), but it appears to prevent signal handlers from
+ * running, even if they're not in the set being waited for.  This makes
+ * it impossible to get the default actions for SIGILL, SIGSEGV, etc.
+ * Instead of messing with it, we just use sigsuspend() instead.
+ */
+#undef HAVE_SIGWAIT
+/*!
+ * We need to remember which thread is the main thread...
+ */
+static pthread_t               main_thread;
+#endif
+
+#ifndef HAVE_SIGWAIT
+static void
+exit_action(int arg) {
+       UNUSED(arg);
+       want_shutdown = ISC_TRUE;
+}
+
+static void
+reload_action(int arg) {
+       UNUSED(arg);
+       want_reload = ISC_TRUE;
+}
+#endif
+
+static isc_result_t
+handle_signal(int sig, void (*handler)(int)) {
+       struct sigaction sa;
+       char strbuf[ISC_STRERRORSIZE];
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = handler;
+
+       if (sigfillset(&sa.sa_mask) != 0 ||
+           sigaction(sig, &sa, NULL) < 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_APP,
+                                              ISC_MSG_SIGNALSETUP,
+                                              "handle_signal() %d setup: %s"),
+                                sig, strbuf);
+               return (ISC_R_UNEXPECTED);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_start(void) {
+       isc_result_t result;
+       int presult;
+       sigset_t sset;
+       char strbuf[ISC_STRERRORSIZE];
+
+       /*
+        * Start an ISC library application.
+        */
+
+#ifdef NEED_PTHREAD_INIT
+       /*
+        * BSDI 3.1 seg faults in pthread_sigmask() if we don't do this.
+        */
+       presult = pthread_init();
+       if (presult != 0) {
+               isc__strerror(presult, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_app_start() pthread_init: %s", strbuf);
+               return (ISC_R_UNEXPECTED);
+       }
+#endif
+
+#ifdef HAVE_LINUXTHREADS
+       main_thread = pthread_self();
+#endif
+
+       result = isc_mutex_init(&lock);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+#ifndef HAVE_SIGWAIT
+       /*
+        * Install do-nothing handlers for SIGINT and SIGTERM.
+        *
+        * We install them now because BSDI 3.1 won't block
+        * the default actions, regardless of what we do with
+        * pthread_sigmask().
+        */
+       result = handle_signal(SIGINT, exit_action);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       result = handle_signal(SIGTERM, exit_action);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+#endif
+
+       /*
+        * Always ignore SIGPIPE.
+        */
+       result = handle_signal(SIGPIPE, SIG_IGN);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       /*
+        * On Solaris 2, delivery of a signal whose action is SIG_IGN
+        * will not cause sigwait() to return. We may have inherited
+        * unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent
+        * process (e.g, Solaris cron).  Set an action of SIG_DFL to make
+        * sure sigwait() works as expected.  Only do this for SIGTERM and
+        * SIGINT if we don't have sigwait(), since a different handler is
+        * installed above.
+        */
+       result = handle_signal(SIGHUP, SIG_DFL);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+#ifdef HAVE_SIGWAIT
+       result = handle_signal(SIGTERM, SIG_DFL);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       result = handle_signal(SIGINT, SIG_DFL);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+#endif
+
+#ifdef ISC_PLATFORM_USETHREADS
+       /*
+        * Block SIGHUP, SIGINT, SIGTERM.
+        *
+        * If isc_app_start() is called from the main thread before any other
+        * threads have been created, then the pthread_sigmask() call below
+        * will result in all threads having SIGHUP, SIGINT and SIGTERM
+        * blocked by default, ensuring that only the thread that calls
+        * sigwait() for them will get those signals.
+        */
+       if (sigemptyset(&sset) != 0 ||
+           sigaddset(&sset, SIGHUP) != 0 ||
+           sigaddset(&sset, SIGINT) != 0 ||
+           sigaddset(&sset, SIGTERM) != 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_app_start() sigsetops: %s", strbuf);
+               return (ISC_R_UNEXPECTED);
+       }
+       presult = pthread_sigmask(SIG_BLOCK, &sset, NULL);
+       if (presult != 0) {
+               isc__strerror(presult, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_app_start() pthread_sigmask: %s",
+                                strbuf);
+               return (ISC_R_UNEXPECTED);
+       }
+#else /* ISC_PLATFORM_USETHREADS */
+       /*
+        * Unblock SIGHUP, SIGINT, SIGTERM.
+        *
+        * If we're not using threads, we need to make sure that SIGHUP,
+        * SIGINT and SIGTERM are not inherited as blocked from the parent
+        * process.
+        */
+       if (sigemptyset(&sset) != 0 ||
+           sigaddset(&sset, SIGHUP) != 0 ||
+           sigaddset(&sset, SIGINT) != 0 ||
+           sigaddset(&sset, SIGTERM) != 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_app_start() sigsetops: %s", strbuf);
+               return (ISC_R_UNEXPECTED);
+       }
+       presult = sigprocmask(SIG_UNBLOCK, &sset, NULL);
+       if (presult != 0) {
+               isc__strerror(presult, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_app_start() sigprocmask: %s", strbuf);
+               return (ISC_R_UNEXPECTED);
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       ISC_LIST_INIT(on_run);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
+             void *arg)
+{
+       isc_event_t *event;
+       isc_task_t *cloned_task = NULL;
+       isc_result_t result;
+
+       LOCK(&lock);
+
+       if (running) {
+               result = ISC_R_ALREADYRUNNING;
+               goto unlock;
+       }
+
+       /*
+        * Note that we store the task to which we're going to send the event
+        * in the event's "sender" field.
+        */
+       isc_task_attach(task, &cloned_task);
+       event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN,
+                                  action, arg, sizeof(*event));
+       if (event == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto unlock;
+       }
+
+       ISC_LIST_APPEND(on_run, event, ev_link);
+
+       result = ISC_R_SUCCESS;
+
+ unlock:
+       UNLOCK(&lock);
+
+       return (result);
+}
+
+#ifndef ISC_PLATFORM_USETHREADS
+/*!
+ * Event loop for nonthreaded programs.
+ */
+static isc_result_t
+evloop(void) {
+       isc_result_t result;
+       while (!want_shutdown) {
+               int n;
+               isc_time_t when, now;
+               struct timeval tv, *tvp;
+               isc_socketwait_t *swait;
+               isc_boolean_t readytasks;
+               isc_boolean_t call_timer_dispatch = ISC_FALSE;
+
+               readytasks = isc__taskmgr_ready();
+               if (readytasks) {
+                       tv.tv_sec = 0;
+                       tv.tv_usec = 0;
+                       tvp = &tv;
+                       call_timer_dispatch = ISC_TRUE;
+               } else {
+                       result = isc__timermgr_nextevent(&when);
+                       if (result != ISC_R_SUCCESS)
+                               tvp = NULL;
+                       else {
+                               isc_uint64_t us;
+
+                               TIME_NOW(&now);
+                               us = isc_time_microdiff(&when, &now);
+                               if (us == 0)
+                                       call_timer_dispatch = ISC_TRUE;
+                               tv.tv_sec = us / 1000000;
+                               tv.tv_usec = us % 1000000;
+                               tvp = &tv;
+                       }
+               }
+
+               swait = NULL;
+               n = isc__socketmgr_waitevents(tvp, &swait);
+
+               if (n == 0 || call_timer_dispatch) {
+                       /*
+                        * We call isc__timermgr_dispatch() only when
+                        * necessary, in order to reduce overhead.  If the
+                        * select() call indicates a timeout, we need the
+                        * dispatch.  Even if not, if we set the 0-timeout
+                        * for the select() call, we need to check the timer
+                        * events.  In the 'readytasks' case, there may be no
+                        * timeout event actually, but there is no other way
+                        * to reduce the overhead.
+                        * Note that we do not have to worry about the case
+                        * where a new timer is inserted during the select()
+                        * call, since this loop only runs in the non-thread
+                        * mode.
+                        */
+                       isc__timermgr_dispatch();
+               }
+               if (n > 0)
+                       (void)isc__socketmgr_dispatch(swait);
+               (void)isc__taskmgr_dispatch();
+
+               if (want_reload) {
+                       want_reload = ISC_FALSE;
+                       return (ISC_R_RELOAD);
+               }
+       }
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * This is a gross hack to support waiting for condition
+ * variables in nonthreaded programs in a limited way;
+ * see lib/isc/nothreads/include/isc/condition.h.
+ * We implement isc_condition_wait() by entering the
+ * event loop recursively until the want_shutdown flag
+ * is set by isc_condition_signal().
+ */
+
+/*!
+ * \brief True if we are currently executing in the recursive
+ * event loop.
+ */
+static isc_boolean_t in_recursive_evloop = ISC_FALSE;
+
+/*!
+ * \brief True if we are exiting the event loop as the result of
+ * a call to isc_condition_signal() rather than a shutdown
+ * or reload.
+ */
+static isc_boolean_t signalled = ISC_FALSE;
+
+isc_result_t
+isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) {
+       isc_result_t result;
+
+       UNUSED(cp);
+       UNUSED(mp);
+
+       INSIST(!in_recursive_evloop);
+       in_recursive_evloop = ISC_TRUE;
+
+       INSIST(*mp == 1); /* Mutex must be locked on entry. */
+       --*mp;
+
+       result = evloop();
+       if (result == ISC_R_RELOAD)
+               want_reload = ISC_TRUE;
+       if (signalled) {
+               want_shutdown = ISC_FALSE;
+               signalled = ISC_FALSE;
+       }
+
+       ++*mp;
+       in_recursive_evloop = ISC_FALSE;
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__nothread_signal_hack(isc_condition_t *cp) {
+
+       UNUSED(cp);
+
+       INSIST(in_recursive_evloop);
+
+       want_shutdown = ISC_TRUE;
+       signalled = ISC_TRUE;
+       return (ISC_R_SUCCESS);
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+isc_result_t
+isc_app_run(void) {
+       int result;
+       isc_event_t *event, *next_event;
+       isc_task_t *task;
+#ifdef ISC_PLATFORM_USETHREADS
+       sigset_t sset;
+       char strbuf[ISC_STRERRORSIZE];
+#ifdef HAVE_SIGWAIT
+       int sig;
+#endif
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifdef HAVE_LINUXTHREADS
+       REQUIRE(main_thread == pthread_self());
+#endif
+
+       LOCK(&lock);
+
+       if (!running) {
+               running = ISC_TRUE;
+
+               /*
+                * Post any on-run events (in FIFO order).
+                */
+               for (event = ISC_LIST_HEAD(on_run);
+                    event != NULL;
+                    event = next_event) {
+                       next_event = ISC_LIST_NEXT(event, ev_link);
+                       ISC_LIST_UNLINK(on_run, event, ev_link);
+                       task = event->ev_sender;
+                       event->ev_sender = NULL;
+                       isc_task_sendanddetach(&task, &event);
+               }
+
+       }
+
+       UNLOCK(&lock);
+
+#ifndef HAVE_SIGWAIT
+       /*
+        * Catch SIGHUP.
+        *
+        * We do this here to ensure that the signal handler is installed
+        * (i.e. that it wasn't a "one-shot" handler).
+        */
+       result = handle_signal(SIGHUP, reload_action);
+       if (result != ISC_R_SUCCESS)
+               return (ISC_R_SUCCESS);
+#endif
+
+#ifdef ISC_PLATFORM_USETHREADS
+       /*
+        * There is no danger if isc_app_shutdown() is called before we wait
+        * for signals.  Signals are blocked, so any such signal will simply
+        * be made pending and we will get it when we call sigwait().
+        */
+
+       while (!want_shutdown) {
+#ifdef HAVE_SIGWAIT
+               /*
+                * Wait for SIGHUP, SIGINT, or SIGTERM.
+                */
+               if (sigemptyset(&sset) != 0 ||
+                   sigaddset(&sset, SIGHUP) != 0 ||
+                   sigaddset(&sset, SIGINT) != 0 ||
+                   sigaddset(&sset, SIGTERM) != 0) {
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "isc_app_run() sigsetops: %s", strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+
+#ifndef HAVE_UNIXWARE_SIGWAIT
+               result = sigwait(&sset, &sig);
+               if (result == 0) {
+                       if (sig == SIGINT ||
+                           sig == SIGTERM)
+                               want_shutdown = ISC_TRUE;
+                       else if (sig == SIGHUP)
+                               want_reload = ISC_TRUE;
+               }
+
+#else /* Using UnixWare sigwait semantics. */
+               sig = sigwait(&sset);
+               if (sig >= 0) {
+                       if (sig == SIGINT ||
+                           sig == SIGTERM)
+                               want_shutdown = ISC_TRUE;
+                       else if (sig == SIGHUP)
+                               want_reload = ISC_TRUE;
+               }
+
+#endif /* HAVE_UNIXWARE_SIGWAIT */
+#else  /* Don't have sigwait(). */
+               /*
+                * Listen for all signals.
+                */
+               if (sigemptyset(&sset) != 0) {
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "isc_app_run() sigsetops: %s", strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+               result = sigsuspend(&sset);
+#endif /* HAVE_SIGWAIT */
+
+               if (want_reload) {
+                       want_reload = ISC_FALSE;
+                       return (ISC_R_RELOAD);
+               }
+
+               if (want_shutdown && blocked)
+                       exit(1);
+       }
+
+#else /* ISC_PLATFORM_USETHREADS */
+
+       (void)isc__taskmgr_dispatch();
+
+       result = evloop();
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_shutdown(void) {
+       isc_boolean_t want_kill = ISC_TRUE;
+       char strbuf[ISC_STRERRORSIZE];
+
+       LOCK(&lock);
+
+       REQUIRE(running);
+
+       if (shutdown_requested)
+               want_kill = ISC_FALSE;
+       else
+               shutdown_requested = ISC_TRUE;
+
+       UNLOCK(&lock);
+
+       if (want_kill) {
+#ifdef HAVE_LINUXTHREADS
+               int result;
+
+               result = pthread_kill(main_thread, SIGTERM);
+               if (result != 0) {
+                       isc__strerror(result, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "isc_app_shutdown() pthread_kill: %s",
+                                        strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+#else
+               if (kill(getpid(), SIGTERM) < 0) {
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "isc_app_shutdown() kill: %s", strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+#endif
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_reload(void) {
+       isc_boolean_t want_kill = ISC_TRUE;
+       char strbuf[ISC_STRERRORSIZE];
+
+       LOCK(&lock);
+
+       REQUIRE(running);
+
+       /*
+        * Don't send the reload signal if we're shutting down.
+        */
+       if (shutdown_requested)
+               want_kill = ISC_FALSE;
+
+       UNLOCK(&lock);
+
+       if (want_kill) {
+#ifdef HAVE_LINUXTHREADS
+               int result;
+
+               result = pthread_kill(main_thread, SIGHUP);
+               if (result != 0) {
+                       isc__strerror(result, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "isc_app_reload() pthread_kill: %s",
+                                        strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+#else
+               if (kill(getpid(), SIGHUP) < 0) {
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "isc_app_reload() kill: %s", strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+#endif
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_app_finish(void) {
+       DESTROYLOCK(&lock);
+}
+
+void
+isc_app_block(void) {
+#ifdef ISC_PLATFORM_USETHREADS
+       sigset_t sset;
+#endif /* ISC_PLATFORM_USETHREADS */
+       REQUIRE(running);
+       REQUIRE(!blocked);
+
+       blocked = ISC_TRUE;
+#ifdef ISC_PLATFORM_USETHREADS
+       blockedthread = pthread_self();
+       RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
+                     sigaddset(&sset, SIGINT) == 0 &&
+                     sigaddset(&sset, SIGTERM) == 0);
+       RUNTIME_CHECK(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) == 0);
+#endif /* ISC_PLATFORM_USETHREADS */
+}
+
+void
+isc_app_unblock(void) {
+#ifdef ISC_PLATFORM_USETHREADS
+       sigset_t sset;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       REQUIRE(running);
+       REQUIRE(blocked);
+
+       blocked = ISC_FALSE;
+
+#ifdef ISC_PLATFORM_USETHREADS
+       REQUIRE(blockedthread == pthread_self());
+
+       RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
+                     sigaddset(&sset, SIGINT) == 0 &&
+                     sigaddset(&sset, SIGTERM) == 0);
+       RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0);
+#endif /* ISC_PLATFORM_USETHREADS */
+}
diff --git a/lib/isc/unix/dir.c b/lib/isc/unix/dir.c
new file mode 100644 (file)
index 0000000..9244147
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dir.c,v 1.25.332.3 2009/02/16 23:47:15 tbox Exp $ */
+
+/*! \file
+ * \author  Principal Authors: DCL */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <isc/dir.h>
+#include <isc/magic.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+#define ISC_DIR_MAGIC          ISC_MAGIC('D', 'I', 'R', '*')
+#define VALID_DIR(dir)         ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
+
+void
+isc_dir_init(isc_dir_t *dir) {
+       REQUIRE(dir != NULL);
+
+       dir->entry.name[0] = '\0';
+       dir->entry.length = 0;
+
+       dir->handle = NULL;
+
+       dir->magic = ISC_DIR_MAGIC;
+}
+
+/*!
+ * \brief Allocate workspace and open directory stream. If either one fails,
+ * NULL will be returned.
+ */
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname) {
+       char *p;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(VALID_DIR(dir));
+       REQUIRE(dirname != NULL);
+
+       /*
+        * Copy directory name.  Need to have enough space for the name,
+        * a possible path separator, the wildcard, and the final NUL.
+        */
+       if (strlen(dirname) + 3 > sizeof(dir->dirname))
+               /* XXXDCL ? */
+               return (ISC_R_NOSPACE);
+       strcpy(dir->dirname, dirname);
+
+       /*
+        * Append path separator, if needed, and "*".
+        */
+       p = dir->dirname + strlen(dir->dirname);
+       if (dir->dirname < p && *(p - 1) != '/')
+               *p++ = '/';
+       *p++ = '*';
+       *p++ = '\0';
+
+       /*
+        * Open stream.
+        */
+       dir->handle = opendir(dirname);
+
+       if (dir->handle == NULL)
+               return isc__errno2result(errno);
+
+       return (result);
+}
+
+/*!
+ * \brief Return previously retrieved file or get next one.
+
+ * Unix's dirent has
+ * separate open and read functions, but the Win32 and DOS interfaces open
+ * the dir stream and reads the first file in one operation.
+ */
+isc_result_t
+isc_dir_read(isc_dir_t *dir) {
+       struct dirent *entry;
+
+       REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
+
+       /*
+        * Fetch next file in directory.
+        */
+       entry = readdir(dir->handle);
+
+       if (entry == NULL)
+               return (ISC_R_NOMORE);
+
+       /*
+        * Make sure that the space for the name is long enough.
+        */
+       if (sizeof(dir->entry.name) <= strlen(entry->d_name))
+           return (ISC_R_UNEXPECTED);
+
+       strcpy(dir->entry.name, entry->d_name);
+
+       /*
+        * Some dirents have d_namlen, but it is not portable.
+        */
+       dir->entry.length = strlen(entry->d_name);
+
+       return (ISC_R_SUCCESS);
+}
+
+/*!
+ * \brief Close directory stream.
+ */
+void
+isc_dir_close(isc_dir_t *dir) {
+       REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
+
+       (void)closedir(dir->handle);
+       dir->handle = NULL;
+}
+
+/*!
+ * \brief Reposition directory stream at start.
+ */
+isc_result_t
+isc_dir_reset(isc_dir_t *dir) {
+       REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
+
+       rewinddir(dir->handle);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chdir(const char *dirname) {
+       /*!
+        * \brief Change the current directory to 'dirname'.
+        */
+
+       REQUIRE(dirname != NULL);
+
+       if (chdir(dirname) < 0)
+               return (isc__errno2result(errno));
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chroot(const char *dirname) {
+
+       REQUIRE(dirname != NULL);
+
+#ifdef HAVE_CHROOT
+       if (chroot(dirname) < 0 || chdir("/") < 0)
+               return (isc__errno2result(errno));
+
+       return (ISC_R_SUCCESS);
+#else
+       return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+isc_result_t
+isc_dir_createunique(char *templet) {
+       isc_result_t result;
+       char *x;
+       char *p;
+       int i;
+       int pid;
+
+       REQUIRE(templet != NULL);
+
+       /*!
+        * \brief mkdtemp is not portable, so this emulates it.
+        */
+
+       pid = getpid();
+
+       /*
+        * Replace trailing Xs with the process-id, zero-filled.
+        */
+       for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet;
+            x--, pid /= 10)
+               *x = pid % 10 + '0';
+
+       x++;                    /* Set x to start of ex-Xs. */
+
+       do {
+               i = mkdir(templet, 0700);
+               if (i == 0 || errno != EEXIST)
+                       break;
+
+               /*
+                * The BSD algorithm.
+                */
+               p = x;
+               while (*p != '\0') {
+                       if (isdigit(*p & 0xff))
+                               *p = 'a';
+                       else if (*p != 'z')
+                               ++*p;
+                       else {
+                               /*
+                                * Reset character and move to next.
+                                */
+                               *p++ = 'a';
+                               continue;
+                       }
+
+                       break;
+               }
+
+               if (*p == '\0') {
+                       /*
+                        * Tried all combinations.  errno should already
+                        * be EEXIST, but ensure it is anyway for
+                        * isc__errno2result().
+                        */
+                       errno = EEXIST;
+                       break;
+               }
+       } while (1);
+
+       if (i == -1)
+               result = isc__errno2result(errno);
+       else
+               result = ISC_R_SUCCESS;
+
+       return (result);
+}
diff --git a/lib/isc/unix/entropy.c b/lib/isc/unix/entropy.c
new file mode 100644 (file)
index 0000000..0e9e297
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: entropy.c,v 1.80.332.2 2009/02/16 23:47:15 tbox Exp $ */
+
+/* \file unix/entropy.c
+ * \brief
+ * This is the system dependent part of the ISC entropy API.
+ */
+
+#include <config.h>
+
+#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#ifdef HAVE_NANOSLEEP
+#include <time.h>
+#endif
+#include <unistd.h>
+
+#include <isc/platform.h>
+#include <isc/strerror.h>
+
+#ifdef ISC_PLATFORM_NEEDSYSSELECTH
+#include <sys/select.h>
+#endif
+
+#include "errno2result.h"
+
+/*%
+ * There is only one variable in the entropy data structures that is not
+ * system independent, but pulling the structure that uses it into this file
+ * ultimately means pulling several other independent structures here also to
+ * resolve their interdependencies.  Thus only the problem variable's type
+ * is defined here.
+ */
+#define FILESOURCE_HANDLE_TYPE int
+
+typedef struct {
+       int     handle;
+       enum    {
+               isc_usocketsource_disconnected,
+               isc_usocketsource_connecting,
+               isc_usocketsource_connected,
+               isc_usocketsource_ndesired,
+               isc_usocketsource_wrote,
+               isc_usocketsource_reading
+       } status;
+       size_t  sz_to_recv;
+} isc_entropyusocketsource_t;
+
+#include "../entropy.c"
+
+static unsigned int
+get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
+       isc_entropy_t *ent = source->ent;
+       unsigned char buf[128];
+       int fd = source->sources.file.handle;
+       ssize_t n, ndesired;
+       unsigned int added;
+
+       if (source->bad)
+               return (0);
+
+       desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
+
+       added = 0;
+       while (desired > 0) {
+               ndesired = ISC_MIN(desired, sizeof(buf));
+               n = read(fd, buf, ndesired);
+               if (n < 0) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               goto out;
+                       goto err;
+               }
+               if (n == 0)
+                       goto err;
+
+               entropypool_adddata(ent, buf, n, n * 8);
+               added += n * 8;
+               desired -= n;
+       }
+       goto out;
+
+ err:
+       (void)close(fd);
+       source->sources.file.handle = -1;
+       source->bad = ISC_TRUE;
+
+ out:
+       return (added);
+}
+
+static unsigned int
+get_from_usocketsource(isc_entropysource_t *source, isc_uint32_t desired) {
+       isc_entropy_t *ent = source->ent;
+       unsigned char buf[128];
+       int fd = source->sources.usocket.handle;
+       ssize_t n = 0, ndesired;
+       unsigned int added;
+       size_t sz_to_recv = source->sources.usocket.sz_to_recv;
+
+       if (source->bad)
+               return (0);
+
+       desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
+
+       added = 0;
+       while (desired > 0) {
+               ndesired = ISC_MIN(desired, sizeof(buf));
+ eagain_loop:
+
+               switch ( source->sources.usocket.status ) {
+               case isc_usocketsource_ndesired:
+                       buf[0] = ndesired;
+                       if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) {
+                               if (errno == EWOULDBLOCK || errno == EINTR ||
+                                   errno == ECONNRESET)
+                                       goto out;
+                               goto err;
+                       }
+                       INSIST(n == 1);
+                       source->sources.usocket.status =
+                                               isc_usocketsource_wrote;
+                       goto eagain_loop;
+
+               case isc_usocketsource_connecting:
+               case isc_usocketsource_connected:
+                       buf[0] = 1;
+                       buf[1] = ndesired;
+                       if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) {
+                               if (errno == EWOULDBLOCK || errno == EINTR ||
+                                   errno == ECONNRESET)
+                                       goto out;
+                               goto err;
+                       }
+                       if (n == 1) {
+                               source->sources.usocket.status =
+                                       isc_usocketsource_ndesired;
+                               goto eagain_loop;
+                       }
+                       INSIST(n == 2);
+                       source->sources.usocket.status =
+                                               isc_usocketsource_wrote;
+                       /*FALLTHROUGH*/
+
+               case isc_usocketsource_wrote:
+                       if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) {
+                               if (errno == EAGAIN) {
+                                       /*
+                                        * The problem of EAGAIN (try again
+                                        * later) is a major issue on HP-UX.
+                                        * Solaris actually tries the recvfrom
+                                        * call again, while HP-UX just dies.
+                                        * This code is an attempt to let the
+                                        * entropy pool fill back up (at least
+                                        * that's what I think the problem is.)
+                                        * We go to eagain_loop because if we
+                                        * just "break", then the "desired"
+                                        * amount gets borked.
+                                        */
+#ifdef HAVE_NANOSLEEP
+                                       struct timespec ts;
+
+                                       ts.tv_sec = 0;
+                                       ts.tv_nsec = 1000000;
+                                       nanosleep(&ts, NULL);
+#else
+                                       usleep(1000);
+#endif
+                                       goto eagain_loop;
+                               }
+                               if (errno == EWOULDBLOCK || errno == EINTR)
+                                       goto out;
+                               goto err;
+                       }
+                       source->sources.usocket.status =
+                                       isc_usocketsource_reading;
+                       sz_to_recv = buf[0];
+                       source->sources.usocket.sz_to_recv = sz_to_recv;
+                       if (sz_to_recv > sizeof(buf))
+                               goto err;
+                       /*FALLTHROUGH*/
+
+               case isc_usocketsource_reading:
+                       if (sz_to_recv != 0U) {
+                               n = recv(fd, buf, sz_to_recv, 0);
+                               if (n < 0) {
+                                       if (errno == EWOULDBLOCK ||
+                                           errno == EINTR)
+                                               goto out;
+                                       goto err;
+                               }
+                       } else
+                               n = 0;
+                       break;
+
+               default:
+                       goto err;
+               }
+
+               if ((size_t)n != sz_to_recv)
+                       source->sources.usocket.sz_to_recv -= n;
+               else
+                       source->sources.usocket.status =
+                               isc_usocketsource_connected;
+
+               if (n == 0)
+                       goto out;
+
+               entropypool_adddata(ent, buf, n, n * 8);
+               added += n * 8;
+               desired -= n;
+       }
+       goto out;
+
+ err:
+       close(fd);
+       source->bad = ISC_TRUE;
+       source->sources.usocket.status = isc_usocketsource_disconnected;
+       source->sources.usocket.handle = -1;
+
+ out:
+       return (added);
+}
+
+/*
+ * Poll each source, trying to get data from it to stuff into the entropy
+ * pool.
+ */
+static void
+fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
+       unsigned int added;
+       unsigned int remaining;
+       unsigned int needed;
+       unsigned int nsource;
+       isc_entropysource_t *source;
+
+       REQUIRE(VALID_ENTROPY(ent));
+
+       needed = desired;
+
+       /*
+        * This logic is a little strange, so an explanation is in order.
+        *
+        * If needed is 0, it means we are being asked to "fill to whatever
+        * we think is best."  This means that if we have at least a
+        * partially full pool (say, > 1/4th of the pool) we probably don't
+        * need to add anything.
+        *
+        * Also, we will check to see if the "pseudo" count is too high.
+        * If it is, try to mix in better data.  Too high is currently
+        * defined as 1/4th of the pool.
+        *
+        * Next, if we are asked to add a specific bit of entropy, make
+        * certain that we will do so.  Clamp how much we try to add to
+        * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
+        *
+        * Note that if we are in a blocking mode, we will only try to
+        * get as much data as we need, not as much as we might want
+        * to build up.
+        */
+       if (needed == 0) {
+               REQUIRE(!blocking);
+
+               if ((ent->pool.entropy >= RND_POOLBITS / 4)
+                   && (ent->pool.pseudo <= RND_POOLBITS / 4))
+                       return;
+
+               needed = THRESHOLD_BITS * 4;
+       } else {
+               needed = ISC_MAX(needed, THRESHOLD_BITS);
+               needed = ISC_MIN(needed, RND_POOLBITS);
+       }
+
+       /*
+        * In any case, clamp how much we need to how much we can add.
+        */
+       needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
+
+       /*
+        * But wait!  If we're not yet initialized, we need at least
+        *      THRESHOLD_BITS
+        * of randomness.
+        */
+       if (ent->initialized < THRESHOLD_BITS)
+               needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
+
+       /*
+        * Poll each file source to see if we can read anything useful from
+        * it.  XXXMLG When where are multiple sources, we should keep a
+        * record of which one we last used so we can start from it (or the
+        * next one) to avoid letting some sources build up entropy while
+        * others are always drained.
+        */
+
+       added = 0;
+       remaining = needed;
+       if (ent->nextsource == NULL) {
+               ent->nextsource = ISC_LIST_HEAD(ent->sources);
+               if (ent->nextsource == NULL)
+                       return;
+       }
+       source = ent->nextsource;
+ again_file:
+       for (nsource = 0; nsource < ent->nsources; nsource++) {
+               unsigned int got;
+
+               if (remaining == 0)
+                       break;
+
+               got = 0;
+
+               switch ( source->type ) {
+               case ENTROPY_SOURCETYPE_FILE:
+                       got = get_from_filesource(source, remaining);
+                       break;
+
+               case ENTROPY_SOURCETYPE_USOCKET:
+                       got = get_from_usocketsource(source, remaining);
+                       break;
+               }
+
+               added += got;
+
+               remaining -= ISC_MIN(remaining, got);
+
+               source = ISC_LIST_NEXT(source, link);
+               if (source == NULL)
+                       source = ISC_LIST_HEAD(ent->sources);
+       }
+       ent->nextsource = source;
+
+       if (blocking && remaining != 0) {
+               int fds;
+
+               fds = wait_for_sources(ent);
+               if (fds > 0)
+                       goto again_file;
+       }
+
+       /*
+        * Here, if there are bits remaining to be had and we can block,
+        * check to see if we have a callback source.  If so, call them.
+        */
+       source = ISC_LIST_HEAD(ent->sources);
+       while ((remaining != 0) && (source != NULL)) {
+               unsigned int got;
+
+               got = 0;
+
+               if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
+                       got = get_from_callback(source, remaining, blocking);
+
+               added += got;
+               remaining -= ISC_MIN(remaining, got);
+
+               if (added >= needed)
+                       break;
+
+               source = ISC_LIST_NEXT(source, link);
+       }
+
+       /*
+        * Mark as initialized if we've added enough data.
+        */
+       if (ent->initialized < THRESHOLD_BITS)
+               ent->initialized += added;
+}
+
+static int
+wait_for_sources(isc_entropy_t *ent) {
+       isc_entropysource_t *source;
+       int maxfd, fd;
+       int cc;
+       fd_set reads;
+       fd_set writes;
+
+       maxfd = -1;
+       FD_ZERO(&reads);
+       FD_ZERO(&writes);
+
+       source = ISC_LIST_HEAD(ent->sources);
+       while (source != NULL) {
+               if (source->type == ENTROPY_SOURCETYPE_FILE) {
+                       fd = source->sources.file.handle;
+                       if (fd >= 0) {
+                               maxfd = ISC_MAX(maxfd, fd);
+                               FD_SET(fd, &reads);
+                       }
+               }
+               if (source->type == ENTROPY_SOURCETYPE_USOCKET) {
+                       fd = source->sources.usocket.handle;
+                       if (fd >= 0) {
+                               switch (source->sources.usocket.status) {
+                               case isc_usocketsource_disconnected:
+                                       break;
+                               case isc_usocketsource_connecting:
+                               case isc_usocketsource_connected:
+                               case isc_usocketsource_ndesired:
+                                       maxfd = ISC_MAX(maxfd, fd);
+                                       FD_SET(fd, &writes);
+                                       break;
+                               case isc_usocketsource_wrote:
+                               case isc_usocketsource_reading:
+                                       maxfd = ISC_MAX(maxfd, fd);
+                                       FD_SET(fd, &reads);
+                                       break;
+                               }
+                       }
+               }
+               source = ISC_LIST_NEXT(source, link);
+       }
+
+       if (maxfd < 0)
+               return (-1);
+
+       cc = select(maxfd + 1, &reads, &writes, NULL, NULL);
+       if (cc < 0)
+               return (-1);
+
+       return (cc);
+}
+
+static void
+destroyfilesource(isc_entropyfilesource_t *source) {
+       (void)close(source->handle);
+}
+
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source) {
+       close(source->handle);
+}
+
+/*
+ * Make a fd non-blocking
+ */
+static isc_result_t
+make_nonblock(int fd) {
+       int ret;
+       int flags;
+       char strbuf[ISC_STRERRORSIZE];
+#ifdef USE_FIONBIO_IOCTL
+       int on = 1;
+
+       ret = ioctl(fd, FIONBIO, (char *)&on);
+#else
+       flags = fcntl(fd, F_GETFL, 0);
+       flags |= PORT_NONBLOCK;
+       ret = fcntl(fd, F_SETFL, flags);
+#endif
+
+       if (ret == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+#ifdef USE_FIONBIO_IOCTL
+                                "ioctl(%d, FIONBIO, &on): %s", fd,
+#else
+                                "fcntl(%d, F_SETFL, %d): %s", fd, flags,
+#endif
+                                strbuf);
+
+               return (ISC_R_UNEXPECTED);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
+       int fd;
+       struct stat _stat;
+       isc_boolean_t is_usocket = ISC_FALSE;
+       isc_boolean_t is_connected = ISC_FALSE;
+       isc_result_t ret;
+       isc_entropysource_t *source;
+
+       REQUIRE(VALID_ENTROPY(ent));
+       REQUIRE(fname != NULL);
+
+       LOCK(&ent->lock);
+
+       if (stat(fname, &_stat) < 0) {
+               ret = isc__errno2result(errno);
+               goto errout;
+       }
+       /*
+        * Solaris 2.5.1 does not have support for sockets (S_IFSOCK),
+        * but it does return type S_IFIFO (the OS believes that
+        * the socket is a fifo).  This may be an issue if we tell
+        * the program to look at an actual FIFO as its source of
+        * entropy.
+        */
+#if defined(S_ISSOCK)
+       if (S_ISSOCK(_stat.st_mode))
+               is_usocket = ISC_TRUE;
+#endif
+#if defined(S_ISFIFO) && defined(sun)
+       if (S_ISFIFO(_stat.st_mode))
+               is_usocket = ISC_TRUE;
+#endif
+       if (is_usocket)
+               fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       else
+               fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0);
+
+       if (fd < 0) {
+               ret = isc__errno2result(errno);
+               goto errout;
+       }
+
+       ret = make_nonblock(fd);
+       if (ret != ISC_R_SUCCESS)
+               goto closefd;
+
+       if (is_usocket) {
+               struct sockaddr_un sname;
+
+               memset(&sname, 0, sizeof(sname));
+               sname.sun_family = AF_UNIX;
+               strncpy(sname.sun_path, fname, sizeof(sname.sun_path));
+               sname.sun_path[sizeof(sname.sun_path)-1] = '0';
+#ifdef ISC_PLATFORM_HAVESALEN
+#if !defined(SUN_LEN)
+#define SUN_LEN(su) \
+       (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+               sname.sun_len = SUN_LEN(&sname);
+#endif
+
+               if (connect(fd, (struct sockaddr *) &sname,
+                           sizeof(struct sockaddr_un)) < 0) {
+                       if (errno != EINPROGRESS) {
+                               ret = isc__errno2result(errno);
+                               goto closefd;
+                       }
+               } else
+                       is_connected = ISC_TRUE;
+       }
+
+       source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+       if (source == NULL) {
+               ret = ISC_R_NOMEMORY;
+               goto closefd;
+       }
+
+       /*
+        * From here down, no failures can occur.
+        */
+       source->magic = SOURCE_MAGIC;
+       source->ent = ent;
+       source->total = 0;
+       source->bad = ISC_FALSE;
+       memset(source->name, 0, sizeof(source->name));
+       ISC_LINK_INIT(source, link);
+       if (is_usocket) {
+               source->sources.usocket.handle = fd;
+               if (is_connected)
+                       source->sources.usocket.status =
+                                       isc_usocketsource_connected;
+               else
+                       source->sources.usocket.status =
+                                       isc_usocketsource_connecting;
+               source->sources.usocket.sz_to_recv = 0;
+               source->type = ENTROPY_SOURCETYPE_USOCKET;
+       } else {
+               source->sources.file.handle = fd;
+               source->type = ENTROPY_SOURCETYPE_FILE;
+       }
+
+       /*
+        * Hook it into the entropy system.
+        */
+       ISC_LIST_APPEND(ent->sources, source, link);
+       ent->nsources++;
+
+       UNLOCK(&ent->lock);
+       return (ISC_R_SUCCESS);
+
+ closefd:
+       (void)close(fd);
+
+ errout:
+       UNLOCK(&ent->lock);
+
+       return (ret);
+}
diff --git a/lib/isc/unix/errno2result.c b/lib/isc/unix/errno2result.c
new file mode 100644 (file)
index 0000000..606c560
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: errno2result.c,v 1.17 2007/06/19 23:47:18 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/result.h>
+#include <isc/strerror.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+/*%
+ * Convert a POSIX errno value into an isc_result_t.  The
+ * list of supported errno values is not complete; new users
+ * of this function should add any expected errors that are
+ * not already there.
+ */
+isc_result_t
+isc__errno2result(int posixerrno) {
+       char strbuf[ISC_STRERRORSIZE];
+
+       switch (posixerrno) {
+       case ENOTDIR:
+       case ELOOP:
+       case EINVAL:            /* XXX sometimes this is not for files */
+       case ENAMETOOLONG:
+       case EBADF:
+               return (ISC_R_INVALIDFILE);
+       case ENOENT:
+               return (ISC_R_FILENOTFOUND);
+       case EACCES:
+       case EPERM:
+               return (ISC_R_NOPERM);
+       case EEXIST:
+               return (ISC_R_FILEEXISTS);
+       case EIO:
+               return (ISC_R_IOERROR);
+       case ENOMEM:
+               return (ISC_R_NOMEMORY);
+       case ENFILE:    
+       case EMFILE:
+               return (ISC_R_TOOMANYOPENFILES);
+       case EPIPE:
+#ifdef ECONNRESET
+       case ECONNRESET:
+#endif
+#ifdef ECONNABORTED
+       case ECONNABORTED:
+#endif
+               return (ISC_R_CONNECTIONRESET);
+#ifdef ENOTCONN
+       case ENOTCONN:
+               return (ISC_R_NOTCONNECTED);
+#endif
+#ifdef ETIMEDOUT
+       case ETIMEDOUT:
+               return (ISC_R_TIMEDOUT);
+#endif
+#ifdef ENOBUFS
+       case ENOBUFS:
+               return (ISC_R_NORESOURCES);
+#endif
+#ifdef EAFNOSUPPORT
+       case EAFNOSUPPORT:
+               return (ISC_R_FAMILYNOSUPPORT);
+#endif
+#ifdef ENETDOWN
+       case ENETDOWN:
+               return (ISC_R_NETDOWN);
+#endif
+#ifdef EHOSTDOWN
+       case EHOSTDOWN:
+               return (ISC_R_HOSTDOWN);
+#endif
+#ifdef ENETUNREACH
+       case ENETUNREACH:
+               return (ISC_R_NETUNREACH);
+#endif
+#ifdef EHOSTUNREACH
+       case EHOSTUNREACH:
+               return (ISC_R_HOSTUNREACH);
+#endif
+#ifdef EADDRINUSE
+       case EADDRINUSE:
+               return (ISC_R_ADDRINUSE);
+#endif
+       case EADDRNOTAVAIL:
+               return (ISC_R_ADDRNOTAVAIL);
+       case ECONNREFUSED:
+               return (ISC_R_CONNREFUSED);
+       default:
+               isc__strerror(posixerrno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "unable to convert errno "
+                                "to isc_result: %d: %s",
+                                posixerrno, strbuf);
+               /*
+                * XXXDCL would be nice if perhaps this function could
+                * return the system's error string, so the caller
+                * might have something more descriptive than "unexpected
+                * error" to log with.
+                */
+               return (ISC_R_UNEXPECTED);
+       }
+}
diff --git a/lib/isc/unix/errno2result.h b/lib/isc/unix/errno2result.h
new file mode 100644 (file)
index 0000000..b5b658d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: errno2result.h,v 1.12 2007/06/19 23:47:18 tbox Exp $ */
+
+#ifndef UNIX_ERRNO2RESULT_H
+#define UNIX_ERRNO2RESULT_H 1
+
+/*! \file */
+
+/* XXXDCL this should be moved to lib/isc/include/isc/errno2result.h. */
+
+#include <errno.h>             /* Provides errno. */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc__errno2result(int posixerrno);
+
+ISC_LANG_ENDDECLS
+
+#endif /* UNIX_ERRNO2RESULT_H */
diff --git a/lib/isc/unix/file.c b/lib/isc/unix/file.c
new file mode 100644 (file)
index 0000000..748aee8
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1987, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: file.c,v 1.51.332.2 2009/02/16 23:47:15 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <time.h>              /* Required for utimes on some platforms. */
+#include <unistd.h>            /* Required for mkstemp on NetBSD. */
+
+
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <isc/dir.h>
+#include <isc/file.h>
+#include <isc/log.h>
+#include <isc/random.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+/*
+ * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
+ * it might be good to provide a mechanism that allows for the results
+ * of a previous stat() to be used again without having to do another stat,
+ * such as perl's mechanism of using "_" in place of a file name to indicate
+ * that the results of the last stat should be used.  But then you get into
+ * annoying MP issues.   BTW, Win32 has stat().
+ */
+static isc_result_t
+file_stats(const char *file, struct stat *stats) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(file != NULL);
+       REQUIRE(stats != NULL);
+
+       if (stat(file, stats) != 0)
+               result = isc__errno2result(errno);
+
+       return (result);
+}
+
+isc_result_t
+isc_file_getmodtime(const char *file, isc_time_t *time) {
+       isc_result_t result;
+       struct stat stats;
+
+       REQUIRE(file != NULL);
+       REQUIRE(time != NULL);
+
+       result = file_stats(file, &stats);
+
+       if (result == ISC_R_SUCCESS)
+               /*
+                * XXXDCL some operating systems provide nanoseconds, too,
+                * such as BSD/OS via st_mtimespec.
+                */
+               isc_time_set(time, stats.st_mtime, 0);
+
+       return (result);
+}
+
+isc_result_t
+isc_file_settime(const char *file, isc_time_t *time) {
+       struct timeval times[2];
+
+       REQUIRE(file != NULL && time != NULL);
+
+       /*
+        * tv_sec is at least a 32 bit quantity on all platforms we're
+        * dealing with, but it is signed on most (all?) of them,
+        * so we need to make sure the high bit isn't set.  This unfortunately
+        * loses when either:
+        *   * tv_sec becomes a signed 64 bit integer but long is 32 bits
+        *      and isc_time_seconds > LONG_MAX, or
+        *   * isc_time_seconds is changed to be > 32 bits but long is 32 bits
+        *      and isc_time_seconds has at least 33 significant bits.
+        */
+       times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(time);
+
+       /*
+        * Here is the real check for the high bit being set.
+        */
+       if ((times[0].tv_sec &
+            (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0)
+               return (ISC_R_RANGE);
+
+       /*
+        * isc_time_nanoseconds guarantees a value that divided by 1000 will
+        * fit into the minimum possible size tv_usec field.  Unfortunately,
+        * we don't know what that type is so can't cast directly ... but
+        * we can at least cast to signed so the IRIX compiler shuts up.
+        */
+       times[0].tv_usec = times[1].tv_usec =
+               (isc_int32_t)(isc_time_nanoseconds(time) / 1000);
+
+       if (utimes(file, times) < 0)
+               return (isc__errno2result(errno));
+
+       return (ISC_R_SUCCESS);
+}
+
+#undef TEMPLATE
+#define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */
+
+isc_result_t
+isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
+       return (isc_file_template(path, TEMPLATE, buf, buflen));
+}
+
+isc_result_t
+isc_file_template(const char *path, const char *templet, char *buf,
+                       size_t buflen) {
+       char *s;
+
+       REQUIRE(path != NULL);
+       REQUIRE(templet != NULL);
+       REQUIRE(buf != NULL);
+
+       s = strrchr(templet, '/');
+       if (s != NULL)
+               templet = s + 1;
+
+       s = strrchr(path, '/');
+
+       if (s != NULL) {
+               if ((s - path + 1 + strlen(templet) + 1) > buflen)
+                       return (ISC_R_NOSPACE);
+
+               strncpy(buf, path, s - path + 1);
+               buf[s - path + 1] = '\0';
+               strcat(buf, templet);
+       } else {
+               if ((strlen(templet) + 1) > buflen)
+                       return (ISC_R_NOSPACE);
+
+               strcpy(buf, templet);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+static char alphnum[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+isc_result_t
+isc_file_renameunique(const char *file, char *templet) {
+       char *x;
+       char *cp;
+       isc_uint32_t which;
+
+       REQUIRE(file != NULL);
+       REQUIRE(templet != NULL);
+
+       cp = templet;
+       while (*cp != '\0')
+               cp++;
+       if (cp == templet)
+               return (ISC_R_FAILURE);
+
+       x = cp--;
+       while (cp >= templet && *cp == 'X') {
+               isc_random_get(&which);
+               *cp = alphnum[which % (sizeof(alphnum) - 1)];
+               x = cp--;
+       }
+       while (link(file, templet) == -1) {
+               if (errno != EEXIST)
+                       return (isc__errno2result(errno));
+               for (cp = x;;) {
+                       char *t;
+                       if (*cp == '\0')
+                               return (ISC_R_FAILURE);
+                       t = strchr(alphnum, *cp);
+                       if (t == NULL || *++t == '\0')
+                               *cp++ = alphnum[0];
+                       else {
+                               *cp = *t;
+                               break;
+                       }
+               }
+       }
+       if (unlink(file) < 0)
+               if (errno != ENOENT)
+                       return (isc__errno2result(errno));
+       return (ISC_R_SUCCESS);
+}
+
+
+isc_result_t
+isc_file_openunique(char *templet, FILE **fp) {
+       int fd;
+       FILE *f;
+       isc_result_t result = ISC_R_SUCCESS;
+       char *x;
+       char *cp;
+       isc_uint32_t which;
+       int mode;
+
+       REQUIRE(templet != NULL);
+       REQUIRE(fp != NULL && *fp == NULL);
+
+       cp = templet;
+       while (*cp != '\0')
+               cp++;
+       if (cp == templet)
+               return (ISC_R_FAILURE);
+
+       x = cp--;
+       while (cp >= templet && *cp == 'X') {
+               isc_random_get(&which);
+               *cp = alphnum[which % (sizeof(alphnum) - 1)];
+               x = cp--;
+       }
+
+       mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+
+       while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) {
+               if (errno != EEXIST)
+                       return (isc__errno2result(errno));
+               for (cp = x;;) {
+                       char *t;
+                       if (*cp == '\0')
+                               return (ISC_R_FAILURE);
+                       t = strchr(alphnum, *cp);
+                       if (t == NULL || *++t == '\0')
+                               *cp++ = alphnum[0];
+                       else {
+                               *cp = *t;
+                               break;
+                       }
+               }
+       }
+       f = fdopen(fd, "w+");
+       if (f == NULL) {
+               result = isc__errno2result(errno);
+               if (remove(templet) < 0) {
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_FILE, ISC_LOG_ERROR,
+                                     "remove '%s': failed", templet);
+               }
+               (void)close(fd);
+       } else
+               *fp = f;
+
+       return (result);
+}
+
+isc_result_t
+isc_file_remove(const char *filename) {
+       int r;
+
+       REQUIRE(filename != NULL);
+
+       r = unlink(filename);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_file_rename(const char *oldname, const char *newname) {
+       int r;
+
+       REQUIRE(oldname != NULL);
+       REQUIRE(newname != NULL);
+
+       r = rename(oldname, newname);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_boolean_t
+isc_file_exists(const char *pathname) {
+       struct stat stats;
+
+       REQUIRE(pathname != NULL);
+
+       return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
+}
+
+isc_boolean_t
+isc_file_isabsolute(const char *filename) {
+       REQUIRE(filename != NULL);
+       return (ISC_TF(filename[0] == '/'));
+}
+
+isc_boolean_t
+isc_file_iscurrentdir(const char *filename) {
+       REQUIRE(filename != NULL);
+       return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
+}
+
+isc_boolean_t
+isc_file_ischdiridempotent(const char *filename) {
+       REQUIRE(filename != NULL);
+       if (isc_file_isabsolute(filename))
+               return (ISC_TRUE);
+       if (isc_file_iscurrentdir(filename))
+               return (ISC_TRUE);
+       return (ISC_FALSE);
+}
+
+const char *
+isc_file_basename(const char *filename) {
+       char *s;
+
+       REQUIRE(filename != NULL);
+
+       s = strrchr(filename, '/');
+       if (s == NULL)
+               return (filename);
+
+       return (s + 1);
+}
+
+isc_result_t
+isc_file_progname(const char *filename, char *buf, size_t buflen) {
+       const char *base;
+       size_t len;
+
+       REQUIRE(filename != NULL);
+       REQUIRE(buf != NULL);
+
+       base = isc_file_basename(filename);
+       len = strlen(base) + 1;
+
+       if (len > buflen)
+               return (ISC_R_NOSPACE);
+       memcpy(buf, base, len);
+
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * Put the absolute name of the current directory into 'dirname', which is
+ * a buffer of at least 'length' characters.  End the string with the
+ * appropriate path separator, such that the final product could be
+ * concatenated with a relative pathname to make a valid pathname string.
+ */
+static isc_result_t
+dir_current(char *dirname, size_t length) {
+       char *cwd;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(dirname != NULL);
+       REQUIRE(length > 0U);
+
+       cwd = getcwd(dirname, length);
+
+       if (cwd == NULL) {
+               if (errno == ERANGE)
+                       result = ISC_R_NOSPACE;
+               else
+                       result = isc__errno2result(errno);
+       } else {
+               if (strlen(dirname) + 1 == length)
+                       result = ISC_R_NOSPACE;
+               else if (dirname[1] != '\0')
+                       strcat(dirname, "/");
+       }
+
+       return (result);
+}
+
+isc_result_t
+isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
+       isc_result_t result;
+       result = dir_current(path, pathlen);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       if (strlen(path) + strlen(filename) + 1 > pathlen)
+               return (ISC_R_NOSPACE);
+       strcat(path, filename);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_truncate(const char *filename, isc_offset_t size) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       if (truncate(filename, size) < 0)
+               result = isc__errno2result(errno);
+       return (result);
+}
diff --git a/lib/isc/unix/fsaccess.c b/lib/isc/unix/fsaccess.c
new file mode 100644 (file)
index 0000000..a2bd89a
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: fsaccess.c,v 1.13 2007/06/19 23:47:18 tbox Exp $ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+
+#include "errno2result.h"
+
+/*! \file
+ * \brief
+ * The OS-independent part of the API is in lib/isc.
+ */
+#include "../fsaccess.c"
+
+isc_result_t
+isc_fsaccess_set(const char *path, isc_fsaccess_t access) {
+       struct stat statb;
+       mode_t mode;
+       isc_boolean_t is_dir = ISC_FALSE;
+       isc_fsaccess_t bits;
+       isc_result_t result;
+
+       if (stat(path, &statb) != 0)
+               return (isc__errno2result(errno));
+
+       if ((statb.st_mode & S_IFDIR) != 0)
+               is_dir = ISC_TRUE;
+       else if ((statb.st_mode & S_IFREG) == 0)
+               return (ISC_R_INVALIDFILE);
+
+       result = check_bad_bits(access, is_dir);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       /*
+        * Done with checking bad bits.  Set mode_t.
+        */
+       mode = 0;
+
+#define SET_AND_CLEAR1(modebit) \
+       if ((access & bits) != 0) { \
+               mode |= modebit; \
+               access &= ~bits; \
+       }
+#define SET_AND_CLEAR(user, group, other) \
+       SET_AND_CLEAR1(user); \
+       bits <<= STEP; \
+       SET_AND_CLEAR1(group); \
+       bits <<= STEP; \
+       SET_AND_CLEAR1(other);
+
+       bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY;
+
+       SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH);
+
+       bits = ISC_FSACCESS_WRITE |
+              ISC_FSACCESS_CREATECHILD |
+              ISC_FSACCESS_DELETECHILD;
+
+       SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH);
+
+       bits = ISC_FSACCESS_EXECUTE |
+              ISC_FSACCESS_ACCESSCHILD;
+
+       SET_AND_CLEAR(S_IXUSR, S_IXGRP, S_IXOTH);
+
+       INSIST(access == 0);
+
+       if (chmod(path, mode) < 0)
+               return (isc__errno2result(errno));
+
+       return (ISC_R_SUCCESS);
+}
index f20c1b3589b3fc68b562f86eb1c1ecf1e0b98260..b576d4632fbb03357b2fcea662aa03ff8464a24d 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ifiter_getifaddrs.c,v 1.2.68.3 2004/03/06 08:14:59 marka Exp $ */
+/* $Id: ifiter_getifaddrs.c,v 1.11 2008/03/20 23:47:00 tbox Exp $ */
 
-/*
+/*! \file
+ * \brief
  * Obtain the list of network interfaces using the getifaddrs(3) library.
  */
 
 #include <ifaddrs.h>
 
+/*% Iterator Magic */
 #define IFITER_MAGIC           ISC_MAGIC('I', 'F', 'I', 'G')
+/*% Valid Iterator */
 #define VALID_IFITER(t)                ISC_MAGIC_VALID(t, IFITER_MAGIC)
 
+#ifdef __linux
+static isc_boolean_t seenv6 = ISC_FALSE;
+#endif
+
+/*% Iterator structure */
 struct isc_interfaceiter {
-       unsigned int            magic;          /* Magic number. */
+       unsigned int            magic;          /*%< Magic number. */
        isc_mem_t               *mctx;
-       void                    *buf;           /* (unused) */
-       unsigned int            bufsize;        /* (always 0) */
-       struct ifaddrs          *ifaddrs;       /* List of ifaddrs */
-       struct ifaddrs          *pos;           /* Ptr to current ifaddr */
-       isc_interface_t         current;        /* Current interface data. */
-       isc_result_t            result;         /* Last result code. */
+       void                    *buf;           /*%< (unused) */
+       unsigned int            bufsize;        /*%< (always 0) */
+       struct ifaddrs          *ifaddrs;       /*%< List of ifaddrs */
+       struct ifaddrs          *pos;           /*%< Ptr to current ifaddr */
+       isc_interface_t         current;        /*%< Current interface data. */
+       isc_result_t            result;         /*%< Last result code. */
+#ifdef  __linux
+       FILE *                  proc;
+       char                    entry[ISC_IF_INET6_SZ];
+       isc_result_t            valid;
+#endif
 };
 
 isc_result_t
@@ -43,6 +56,7 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        isc_result_t result;
        char strbuf[ISC_STRERRORSIZE];
 
+       REQUIRE(mctx != NULL);
        REQUIRE(iterp != NULL);
        REQUIRE(*iterp == NULL);
 
@@ -54,6 +68,17 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        iter->buf = NULL;
        iter->bufsize = 0;
        iter->ifaddrs = NULL;
+#ifdef __linux
+       /*
+        * Only open "/proc/net/if_inet6" if we have never seen a IPv6
+        * address returned by getifaddrs().
+        */
+       if (!seenv6)
+               iter->proc = fopen("/proc/net/if_inet6", "r");
+       else
+               iter->proc = NULL;
+       iter->valid = ISC_R_FAILURE;
+#endif
 
        if (getifaddrs(&iter->ifaddrs) < 0) {
                isc__strerror(errno, strbuf, sizeof(strbuf));
@@ -80,6 +105,10 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        return (ISC_R_SUCCESS);
 
  failure:
+#ifdef __linux
+       if (iter->proc != NULL)
+               fclose(iter->proc);
+#endif
        if (iter->ifaddrs != NULL) /* just in case */
                freeifaddrs(iter->ifaddrs);
        isc_mem_put(mctx, iter, sizeof(*iter));
@@ -103,14 +132,26 @@ internal_current(isc_interfaceiter_t *iter) {
 
        ifa = iter->pos;
 
+#ifdef __linux
+       if (iter->pos == NULL)
+               return (linux_if_inet6_current(iter));
+#endif
+
        INSIST(ifa != NULL);
        INSIST(ifa->ifa_name != NULL);
-       INSIST(ifa->ifa_addr != NULL);
+
+       if (ifa->ifa_addr == NULL)
+               return (ISC_R_IGNORE);
 
        family = ifa->ifa_addr->sa_family;
        if (family != AF_INET && family != AF_INET6)
                return (ISC_R_IGNORE);
 
+#ifdef __linux
+       if (family == AF_INET6)
+               seenv6 = ISC_TRUE;
+#endif
+
        memset(&iter->current, 0, sizeof(iter->current));
 
        namelen = strlen(ifa->ifa_name);
@@ -131,15 +172,6 @@ internal_current(isc_interfaceiter_t *iter) {
        if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
                iter->current.flags |= INTERFACE_F_LOOPBACK;
 
-       if ((ifa->ifa_flags & IFF_BROADCAST) != 0) {
-               iter->current.flags |= INTERFACE_F_BROADCAST;
-       }
-
-#ifdef IFF_MULTICAST
-       if ((ifa->ifa_flags & IFF_MULTICAST) != 0) {
-               iter->current.flags |= INTERFACE_F_MULTICAST;
-       }
-#endif
        iter->current.af = family;
 
        get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
@@ -149,15 +181,10 @@ internal_current(isc_interfaceiter_t *iter) {
                         ifa->ifa_name);
 
        if (ifa->ifa_dstaddr != NULL &&
-           (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
+           (iter->current.flags & IFF_POINTOPOINT) != 0)
                get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
                         ifa->ifa_name);
 
-       if (ifa->ifa_broadaddr != NULL &&
-           (iter->current.flags & INTERFACE_F_BROADCAST) != 0)
-               get_addr(family, &iter->current.broadcast, ifa->ifa_broadaddr,
-                        ifa->ifa_name);
-
        return (ISC_R_SUCCESS);
 }
 
@@ -170,16 +197,28 @@ internal_current(isc_interfaceiter_t *iter) {
  */
 static isc_result_t
 internal_next(isc_interfaceiter_t *iter) {
-       iter->pos = iter->pos->ifa_next;
 
-       if (iter->pos == NULL)
+       if (iter->pos != NULL)
+               iter->pos = iter->pos->ifa_next;
+       if (iter->pos == NULL) {
+#ifdef __linux
+               if (!seenv6)
+                       return (linux_if_inet6_next(iter));
+#endif
                return (ISC_R_NOMORE);
+       }
 
        return (ISC_R_SUCCESS);
 }
 
 static void
 internal_destroy(isc_interfaceiter_t *iter) {
+
+#ifdef __linux
+       if (iter->proc != NULL)
+               fclose(iter->proc);
+       iter->proc = NULL;
+#endif
        if (iter->ifaddrs)
                freeifaddrs(iter->ifaddrs);
        iter->ifaddrs = NULL;
@@ -187,5 +226,9 @@ internal_destroy(isc_interfaceiter_t *iter) {
 
 static
 void internal_first(isc_interfaceiter_t *iter) {
+
+#ifdef __linux
+       linux_if_inet6_first(iter);
+#endif
        iter->pos = iter->ifaddrs;
 }
index e069560b0e4978535a1337e62acd4fa0f48b4acf..a9d29bca5ff588951621dae4dba93e85fc9fbcba 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ifiter_ioctl.c,v 1.19.2.5.2.14 2004/06/22 04:40:23 marka Exp $ */
+/* $Id: ifiter_ioctl.c,v 1.60.120.2 2009/01/18 23:47:41 tbox Exp $ */
 
-/*
+/*! \file
+ * \brief
  * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
  * See netintro(4).
  */
@@ -38,9 +39,7 @@
 #define lifr_addr iflr_addr
 #define lifr_name iflr_name
 #define lifr_dstaddr iflr_dstaddr
-#define lifr_broadaddr iflr_broadaddr
 #define lifr_flags iflr_flags
-#define lifr_index iflr_index
 #define ss_family sa_family
 #define LIFREQ if_laddrreq
 #else
@@ -51,9 +50,6 @@
 #define IFITER_MAGIC           ISC_MAGIC('I', 'F', 'I', 'T')
 #define VALID_IFITER(t)                ISC_MAGIC_VALID(t, IFITER_MAGIC)
 
-#define ISC_IF_INET6_SZ \
-    sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
-
 struct isc_interfaceiter {
        unsigned int            magic;          /* Magic number. */
        isc_mem_t               *mctx;
@@ -83,7 +79,6 @@ struct isc_interfaceiter {
        FILE *                  proc;
        char                    entry[ISC_IF_INET6_SZ];
        isc_result_t            valid;
-       isc_boolean_t           first;
 #endif
        isc_interface_t         current;        /* Current interface data. */
        isc_result_t            result;         /* Last result code. */
@@ -95,7 +90,7 @@ struct isc_interfaceiter {
 #endif
 
 
-/*
+/*%
  * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
  * will have more than a megabyte of interface configuration data.
  */
@@ -105,7 +100,7 @@ struct isc_interfaceiter {
 #ifdef __linux
 #ifndef IF_NAMESIZE
 # ifdef IFNAMSIZ
-#  define IF_NAMESIZE  IFNAMSIZ  
+#  define IF_NAMESIZE  IFNAMSIZ
 # else
 #  define IF_NAMESIZE 16
 # endif
@@ -220,13 +215,15 @@ getbuf6(isc_interfaceiter_t *iter) {
                         */
                        if (errno == ENOENT) {
                                isc__strerror(errno, strbuf, sizeof(strbuf));
-                               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                                isc_msgcat_get(isc_msgcat,
+                               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                             ISC_LOGMODULE_INTERFACE,
+                                             ISC_LOG_DEBUG(1),
+                                             isc_msgcat_get(isc_msgcat,
                                                        ISC_MSGSET_IFITERIOCTL,
                                                        ISC_MSG_GETIFCONFIG,
                                                        "get interface "
                                                        "configuration: %s"),
-                                                strbuf);
+                                              strbuf);
                                result = ISC_R_FAILURE;
                                goto cleanup;
                        }
@@ -294,6 +291,7 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        isc_result_t result;
        char strbuf[ISC_STRERRORSIZE];
 
+       REQUIRE(mctx != NULL);
        REQUIRE(iterp != NULL);
        REQUIRE(*iterp == NULL);
 
@@ -338,9 +336,8 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
                        result = ISC_R_UNEXPECTED;
                        goto socket6_failure;
                }
-               iter->result6 = getbuf6(iter);
-               if (iter->result6 != ISC_R_NOTIMPLEMENTED &&
-                   iter->result6 != ISC_R_SUCCESS)
+               result = iter->result6 = getbuf6(iter);
+               if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
                        goto ioctl6_failure;
        }
 #endif
@@ -371,7 +368,6 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
 #ifdef __linux
        iter->proc = fopen("/proc/net/if_inet6", "r");
        iter->valid = ISC_R_FAILURE;
-       iter->first = ISC_FALSE;
 #endif
        iter->result = ISC_R_FAILURE;
 
@@ -393,7 +389,7 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
                (void) close(iter->socket6);
   socket6_failure:
 #endif
+
        isc_mem_put(mctx, iter, sizeof(*iter));
        return (result);
 }
@@ -421,124 +417,6 @@ internal_current_clusteralias(isc_interfaceiter_t *iter) {
 }
 #endif
 
-#ifdef __linux
-static isc_result_t
-linux_if_inet6_next(isc_interfaceiter_t *iter) {
-       if (iter->proc != NULL &&
-           fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
-               iter->valid = ISC_R_SUCCESS;
-       else
-               iter->valid = ISC_R_NOMORE;
-       return (iter->valid);
-}
-
-static void
-linux_if_inet6_first(isc_interfaceiter_t *iter) {
-       if (iter->proc != NULL) {
-               rewind(iter->proc);
-               (void)linux_if_inet6_next(iter);
-       } else
-               iter->valid = ISC_R_NOMORE;
-       iter->first = ISC_FALSE;
-}
-
-static isc_result_t
-linux_if_inet6_current(isc_interfaceiter_t *iter) {
-       char address[33];
-       char name[IF_NAMESIZE+1];
-       char strbuf[ISC_STRERRORSIZE];
-       struct in6_addr addr6;
-       struct ifreq ifreq;
-       int ifindex, prefix, scope, flags;
-       int res;
-       unsigned int i;
-
-       if (iter->valid != ISC_R_SUCCESS)
-               return (iter->valid);
-       if (iter->proc == NULL) {
-               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                             "/proc/net/if_inet6:iter->proc == NULL");
-               return (ISC_R_FAILURE);
-       }
-
-       /*
-        * Format for /proc/net/if_inet6:
-        * (see iface_proc_info() in net/ipv6/addrconf.c)
-        * <addr6:32> <ifindex:2> <prefix:2> <scope:2> <flags:2> <name:8>
-        */
-       res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
-                    address, &ifindex, &prefix, &scope, &flags, name);
-       if (res != 6) {
-               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                             "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
-                             res);
-               return (ISC_R_FAILURE);
-       }
-       if (strlen(address) != 32) {
-               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                             "/proc/net/if_inet6:strlen(%s) != 32", address);
-               return (ISC_R_FAILURE);
-       }
-       for (i = 0; i < 16; i++) {
-               unsigned char byte;
-               static const char hex[] = "0123456789abcdef";
-               byte = ((index(hex, address[i * 2]) - hex) << 4) |
-                      (index(hex, address[i * 2 + 1]) - hex);
-               addr6.s6_addr[i] = byte;
-       }
-       iter->current.af = AF_INET6;
-       /* iter->current.ifindex = ifindex; */
-       iter->current.flags = 0;
-
-       memset(&ifreq, 0, sizeof(ifreq));
-       INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
-       strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
-
-       if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
-               isc__strerror(errno, strbuf, sizeof(strbuf));
-               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                "%s: getting interface flags: %s",
-                                ifreq.ifr_name, strbuf);
-               return (ISC_R_IGNORE);
-       }
-
-       if ((ifreq.ifr_flags & IFF_UP) != 0)
-               iter->current.flags |= INTERFACE_F_UP;
-#ifdef IFF_POINTOPOINT
-       if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0) 
-               iter->current.flags |= INTERFACE_F_POINTTOPOINT;
-#endif
-       if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
-               iter->current.flags |= INTERFACE_F_LOOPBACK;
-       if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
-               iter->current.flags |= INTERFACE_F_BROADCAST;
-#ifdef IFF_MULTICAST
-       if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
-               iter->current.flags |= INTERFACE_F_MULTICAST;
-#endif
-
-       /*
-        * enable_multicast_if() requires scopeid for setsockopt,
-        * so associate address with their corresponding ifindex.
-        */
-       isc_netaddr_fromin6(&iter->current.address, &addr6);
-       isc_netaddr_setzone(&iter->current.address, (isc_uint32_t)ifindex);
-
-       for (i = 0; i < 16; i++) {
-               if (prefix > 8) {
-                       addr6.s6_addr[i] = 0xff;
-                       prefix -= 8;
-               } else {
-                       addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
-                       prefix = 0;
-               }
-       }
-       isc_netaddr_fromin6(&iter->current.netmask, &addr6);
-       strncpy(iter->current.name, name, sizeof(iter->current.name));
-       return (ISC_R_SUCCESS);
-}
-#endif
-
 /*
  * Get information about the current interface to iter->current.
  * If successful, return ISC_R_SUCCESS.
@@ -559,19 +437,19 @@ internal_current4(isc_interfaceiter_t *iter) {
        char sabuf[256];
 #endif
        int i, bits, prefixlen;
-#ifdef __linux
-       isc_result_t result;
-#endif
 
        REQUIRE(VALID_IFITER(iter));
-       REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
 
+       if (iter->ifc.ifc_len == 0 ||
+           iter->pos == (unsigned int)iter->ifc.ifc_len) {
 #ifdef __linux
-       result = linux_if_inet6_current(iter);
-       if (result != ISC_R_NOMORE)
-               return (result);
-       iter->first = ISC_TRUE;
+               return (linux_if_inet6_current(iter));
+#else
+               return (ISC_R_NOMORE);
 #endif
+       }
+
+       INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);
 
        ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
 
@@ -604,13 +482,11 @@ internal_current4(isc_interfaceiter_t *iter) {
                if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
                        return (ISC_R_IGNORE);
                break;
-#ifdef ISC_PLATFORM_HAVEIPV6
        case AF_INET6:
                if (memcmp(&iter->current.address.type.in6, &in6addr_any,
                           sizeof(in6addr_any)) == 0)
                        return (ISC_R_IGNORE);
                break;
-#endif
        }
 
        /*
@@ -643,16 +519,6 @@ internal_current4(isc_interfaceiter_t *iter) {
        if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
                iter->current.flags |= INTERFACE_F_LOOPBACK;
 
-       if ((ifreq.ifr_flags & IFF_BROADCAST) != 0) {
-               iter->current.flags |= INTERFACE_F_BROADCAST;
-       }
-
-#ifdef IFF_MULTICAST
-       if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) {
-               iter->current.flags |= INTERFACE_F_MULTICAST;
-       }
-#endif
-
        if (family == AF_INET)
                goto inet;
 
@@ -672,7 +538,9 @@ internal_current4(isc_interfaceiter_t *iter) {
        prefixlen = lifreq.lifr_addrlen;
 #else
        isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
-       UNEXPECTED_ERROR(__FILE__, __LINE__,
+       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                     ISC_LOGMODULE_INTERFACE,
+                     ISC_LOG_INFO,
                      isc_msgcat_get(isc_msgcat,
                                     ISC_MSGSET_IFITERIOCTL,
                                     ISC_MSG_GETIFCONFIG,
@@ -726,27 +594,6 @@ internal_current4(isc_interfaceiter_t *iter) {
                         (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
        }
 #endif
-       if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
-               /*
-                * Ignore the HP/UX warning about "integer overflow during
-                * conversion.  It comes from its own macro definition,
-                * and is really hard to shut up.
-                */
-               if (ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq)
-                   < 0) {
-                       isc__strerror(errno, strbuf, sizeof(strbuf));
-                       UNEXPECTED_ERROR(__FILE__, __LINE__,
-                               isc_msgcat_get(isc_msgcat,
-                                              ISC_MSGSET_IFITERIOCTL,
-                                              ISC_MSG_GETDESTADDR,
-                                              "%s: getting "
-                                              "broadcast address: %s"),
-                                        ifreq.ifr_name, strbuf);
-                       return (ISC_R_IGNORE);
-               }
-               get_addr(family, &iter->current.broadcast,
-                        (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name);
-       }
 
        /*
         * Get the network mask.
@@ -818,13 +665,11 @@ internal_current6(isc_interfaceiter_t *iter) {
                if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
                        return (ISC_R_IGNORE);
                break;
-#ifdef ISC_PLATFORM_HAVEIPV6
        case AF_INET6:
                if (memcmp(&iter->current.address.type.in6, &in6addr_any,
                           sizeof(in6addr_any)) == 0)
                        return (ISC_R_IGNORE);
                break;
-#endif
        }
 
        /*
@@ -862,23 +707,13 @@ internal_current6(isc_interfaceiter_t *iter) {
        if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
                iter->current.flags |= INTERFACE_F_LOOPBACK;
 
-       if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) {
-               iter->current.flags |= INTERFACE_F_BROADCAST;
-       }
-
-#ifdef IFF_MULTICAST
-       if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
-               iter->current.flags |= INTERFACE_F_MULTICAST;
-       }
-#endif
-
 #ifdef IFF_POINTOPOINT
        /*
         * If the interface is point-to-point, get the destination address.
         */
        if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
                /*
-                * Ignore the HP/UX warning about "interger overflow during
+                * Ignore the HP/UX warning about "integer overflow during
                 * conversion.  It comes from its own macro definition,
                 * and is really hard to shut up.
                 */
@@ -900,31 +735,6 @@ internal_current6(isc_interfaceiter_t *iter) {
        }
 #endif
 
-#ifdef SIOCGLIFBRDADDR
-       if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
-               /*
-                * Ignore the HP/UX warning about "integer overflow during
-                * conversion.  It comes from its own macro definition,
-                * and is really hard to shut up.
-                */
-               if (ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq)
-                   < 0) {
-                       isc__strerror(errno, strbuf, sizeof(strbuf));
-                       UNEXPECTED_ERROR(__FILE__, __LINE__,
-                               isc_msgcat_get(isc_msgcat,
-                                              ISC_MSGSET_IFITERIOCTL,
-                                              ISC_MSG_GETDESTADDR,
-                                              "%s: getting "
-                                              "broadcast address: %s"),
-                                        lifreq.lifr_name, strbuf);
-                       return (ISC_R_IGNORE);
-               }
-               get_addr(family, &iter->current.broadcast,
-                        (struct sockaddr *)&lifreq.lifr_broadaddr,
-                        lifreq.lifr_name);
-       }
-#endif /* SIOCGLIFBRDADDR */
-
        /*
         * Get the network mask.  Netmask already zeroed.
         */
@@ -999,49 +809,52 @@ internal_current(isc_interfaceiter_t *iter) {
  */
 static isc_result_t
 internal_next4(isc_interfaceiter_t *iter) {
+#ifdef ISC_PLATFORM_HAVESALEN
        struct ifreq *ifrp;
-
-       REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
-
-#ifdef __linux
-       if (linux_if_inet6_next(iter) == ISC_R_SUCCESS)
-               return (ISC_R_SUCCESS);
-       if (!iter->first)
-               return (ISC_R_SUCCESS);
 #endif
-       ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
 
+       if (iter->pos < (unsigned int) iter->ifc.ifc_len) {
 #ifdef ISC_PLATFORM_HAVESALEN
-       if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
-               iter->pos += sizeof(ifrp->ifr_name) + ifrp->ifr_addr.sa_len;
-       else
+               ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
+
+               if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
+                       iter->pos += sizeof(ifrp->ifr_name) +
+                                    ifrp->ifr_addr.sa_len;
+               else
 #endif
-               iter->pos += sizeof(*ifrp);
+                       iter->pos += sizeof(struct ifreq);
 
-       if (iter->pos >= (unsigned int) iter->ifc.ifc_len)
+       } else {
+               INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
+#ifdef __linux
+               return (linux_if_inet6_next(iter));
+#else
                return (ISC_R_NOMORE);
-
+#endif
+       }
        return (ISC_R_SUCCESS);
 }
 
 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
 static isc_result_t
 internal_next6(isc_interfaceiter_t *iter) {
+#ifdef ISC_PLATFORM_HAVESALEN
        struct LIFREQ *ifrp;
-       
+#endif
+
        if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
                return (iter->result6);
 
        REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
 
+#ifdef ISC_PLATFORM_HAVESALEN
        ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
 
-#ifdef ISC_PLATFORM_HAVESALEN
        if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
                iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
        else
 #endif
-               iter->pos6 += sizeof(*ifrp);
+               iter->pos6 += sizeof(struct LIFREQ);
 
        if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
                return (ISC_R_NOMORE);
index 6206e6e5ffb92e1f2201616b09c64185274b8d5b..9d5bf6d9e7c0e01bd27bfcf28606e1088456d5dd 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ifiter_sysctl.c,v 1.14.12.7 2004/03/08 09:04:56 marka Exp $ */
+/* $Id: ifiter_sysctl.c,v 1.25 2007/06/19 23:47:18 tbox Exp $ */
 
-/*
+/*! \file
+ * \brief
  * Obtain the list of network interfaces using sysctl.
  * See TCP/IP Illustrated Volume 2, sections 19.8, 19.14,
  * and 19.16.
@@ -71,6 +72,7 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        size_t bufused;
        char strbuf[ISC_STRERRORSIZE];
 
+       REQUIRE(mctx != NULL);
        REQUIRE(iterp != NULL);
        REQUIRE(*iterp == NULL);
 
@@ -182,15 +184,6 @@ internal_current(isc_interfaceiter_t *iter) {
                if ((ifam->ifam_flags & IFF_LOOPBACK) != 0)
                        iter->current.flags |= INTERFACE_F_LOOPBACK;
 
-               if ((ifam->ifam_flags & IFF_BROADCAST) != 0) {
-                       iter->current.flags |= INTERFACE_F_BROADCAST;
-               }
-#ifdef IFF_MULTICAST
-               if ((ifam->ifam_flags & IFF_MULTICAST) != 0) {
-                       iter->current.flags |= INTERFACE_F_MULTICAST;
-               }
-#endif
-
                /*
                 * This is not an interface address.
                 * Force another iteration.
@@ -263,12 +256,6 @@ internal_current(isc_interfaceiter_t *iter) {
                        get_addr(family, &iter->current.dstaddress, dst_sa,
                                 iter->current.name);
 
-               if (dst_sa != NULL &&
-                   (iter->current.flags & INTERFACE_F_BROADCAST) != 0)
-                       get_addr(family, &iter->current.broadcast, dst_sa,
-                                iter->current.name);
-
-
                return (ISC_R_SUCCESS);
        } else {
                printf(isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERSYSCTL,
index cc85706438d890f1c721da06e7be4d7eec00c508..e4a2ad0fb70d00da43dd979a859d19c492fc9e2b 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dir.h,v 1.17.18.2 2005/04/29 00:17:09 marka Exp $ */
+/* $Id: dir.h,v 1.21 2007/06/19 23:47:19 tbox Exp $ */
 
 /* Principal Authors: DCL */
 
index d30e6dcc62903d2efa0bb99f61c901822a0ce3b0..73feb3b65b3a9061d1c59d9304329ace1f950982 100644 (file)
@@ -1,25 +1,27 @@
 /*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: int.h,v 1.11 2001/01/09 21:58:39 bwelling Exp $ */
+/* $Id: int.h,v 1.16 2007/06/19 23:47:19 tbox Exp $ */
 
 #ifndef ISC_INT_H
 #define ISC_INT_H 1
 
+/*! \file */
+
 typedef char                           isc_int8_t;
 typedef unsigned char                  isc_uint8_t;
 typedef short                          isc_int16_t;
@@ -37,7 +39,7 @@ typedef unsigned long long            isc_uint64_t;
 #define ISC_INT16_MAX  32767
 #define ISC_UINT16_MAX 65535
 
-/*
+/*%
  * Note that "int" is 32 bits on all currently supported Unix-like operating
  * systems, but "long" can be either 32 bits or 64 bits, thus the 32 bit
  * constants are not qualified with "L".
diff --git a/lib/isc/unix/include/isc/keyboard.h b/lib/isc/unix/include/isc/keyboard.h
new file mode 100644 (file)
index 0000000..43f5e7e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: keyboard.h,v 1.11 2007/06/19 23:47:19 tbox Exp $ */
+
+#ifndef ISC_KEYBOARD_H
+#define ISC_KEYBOARD_H 1
+
+/*! \file */
+
+#include <termios.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef struct {
+       int fd;
+       struct termios saved_mode;
+       isc_result_t result;
+} isc_keyboard_t;
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard);
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleepseconds);
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp);
+
+isc_boolean_t
+isc_keyboard_canceled(isc_keyboard_t *keyboard);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_KEYBOARD_H */
index dae59780b69b70eee420b47fbe4eef5eabf67a10..53bebd75a22e7b9a85b44cb80ab95405f4050826 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: net.h,v 1.31.2.2.10.8 2004/04/29 01:31:23 marka Exp $ */
+/* $Id: net.h,v 1.48.84.2 2009/02/16 23:47:15 tbox Exp $ */
 
 #ifndef ISC_NET_H
 #define ISC_NET_H 1
  ***** Module Info
  *****/
 
-/*
+/*! \file
+ * \brief
  * Basic Networking Types
  *
  * This module is responsible for defining the following basic networking
  * types:
  *
- *             struct in_addr
- *             struct in6_addr
- *             struct in6_pktinfo
- *             struct sockaddr
- *             struct sockaddr_in
- *             struct sockaddr_in6
- *             in_port_t
+ *\li          struct in_addr
+ *\li          struct in6_addr
+ *\li          struct in6_pktinfo
+ *\li          struct sockaddr
+ *\li          struct sockaddr_in
+ *\li          struct sockaddr_in6
+ *\li          in_port_t
  *
  * It ensures that the AF_ and PF_ macros are defined.
  *
  *
  * It declares inet_aton(), inet_ntop(), and inet_pton().
  *
- * It ensures that INADDR_LOOPBACK, INADDR_ANY, IN6ADDR_ANY_INIT,
+ * It ensures that #INADDR_LOOPBACK, #INADDR_ANY, #IN6ADDR_ANY_INIT,
  * in6addr_any, and in6addr_loopback are available.
  *
  * It ensures that IN_MULTICAST() is available to check for multicast
  * addresses.
  *
  * MP:
- *     No impact.
+ *\li  No impact.
  *
  * Reliability:
- *     No anticipated impact.
+ *\li  No anticipated impact.
  *
  * Resources:
- *     N/A.
+ *\li  N/A.
  *
  * Security:
- *     No anticipated impact.
+ *\li  No anticipated impact.
  *
  * Standards:
- *     BSD Socket API
- *     RFC 2553
+ *\li  BSD Socket API
+ *\li  RFC2553
  */
 
 /***
 #include <isc/types.h>
 
 #ifdef ISC_PLATFORM_HAVEINADDR6
-#define in6_addr in_addr6      /* Required for pre RFC2133 implementations. */
+#define in6_addr in_addr6      /*%< Required for pre RFC2133 implementations. */
 #endif
 
 #ifdef ISC_PLATFORM_HAVEIPV6
-/*
+#ifndef IN6ADDR_ANY_INIT
+#ifdef s6_addr
+/*%
  * Required for some pre RFC2133 implementations.
  * IN6ADDR_ANY_INIT and IN6ADDR_LOOPBACK_INIT were added in
- * draft-ietf-ipngwg-bsd-api-04.txt or draft-ietf-ipngwg-bsd-api-05.txt.  
+ * draft-ietf-ipngwg-bsd-api-04.txt or draft-ietf-ipngwg-bsd-api-05.txt.
  * If 's6_addr' is defined then assume that there is a union and three
  * levels otherwise assume two levels required.
  */
-#ifndef IN6ADDR_ANY_INIT
-#ifdef s6_addr
 #define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
 #else
 #define IN6ADDR_ANY_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }
 
 #ifndef IN6ADDR_LOOPBACK_INIT
 #ifdef s6_addr
+/*% IPv6 address loopback init */
 #define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
 #else
 #define IN6ADDR_LOOPBACK_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } }
 #endif
 
 #ifndef IN6_IS_ADDR_V4MAPPED
+/*% Is IPv6 address V4 mapped? */
 #define IN6_IS_ADDR_V4MAPPED(x) \
         (memcmp((x)->s6_addr, in6addr_any.s6_addr, 10) == 0 && \
          (x)->s6_addr[10] == 0xff && (x)->s6_addr[11] == 0xff)
 #endif
 
 #ifndef IN6_IS_ADDR_V4COMPAT
+/*% Is IPv6 address V4 compatible? */
 #define IN6_IS_ADDR_V4COMPAT(x) \
         (memcmp((x)->s6_addr, in6addr_any.s6_addr, 12) == 0 && \
         ((x)->s6_addr[12] != 0 || (x)->s6_addr[13] != 0 || \
 #endif
 
 #ifndef IN6_IS_ADDR_MULTICAST
+/*% Is IPv6 address multicast? */
 #define IN6_IS_ADDR_MULTICAST(a)        ((a)->s6_addr[0] == 0xff)
 #endif
 
 #ifndef IN6_IS_ADDR_LINKLOCAL
+/*% Is IPv6 address linklocal? */
 #define IN6_IS_ADDR_LINKLOCAL(a) \
        (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
 #endif
 
 #ifndef IN6_IS_ADDR_SITELOCAL
+/*% is IPv6 address sitelocal? */
 #define IN6_IS_ADDR_SITELOCAL(a) \
        (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
 #endif
 
 
 #ifndef IN6_IS_ADDR_LOOPBACK
+/*% is IPv6 address loopback? */
 #define IN6_IS_ADDR_LOOPBACK(x) \
        (memcmp((x)->s6_addr, in6addr_loopback.s6_addr, 16) == 0)
 #endif
 #endif
 
 #ifndef AF_INET6
+/*% IPv6 */
 #define AF_INET6 99
 #endif
 
 #ifndef PF_INET6
+/*% IPv6 */
 #define PF_INET6 AF_INET6
 #endif
 
 #ifndef INADDR_LOOPBACK
+/*% inaddr loopback */
 #define INADDR_LOOPBACK 0x7f000001UL
 #endif
 
-#if 0
 #ifndef ISC_PLATFORM_HAVEIN6PKTINFO
+/*% IPv6 packet info */
 struct in6_pktinfo {
-       struct in6_addr ipi6_addr;    /* src/dst IPv6 address */
-       unsigned int    ipi6_ifindex; /* send/recv interface index */
+       struct in6_addr ipi6_addr;    /*%< src/dst IPv6 address */
+       unsigned int    ipi6_ifindex; /*%< send/recv interface index */
 };
 #endif
-#endif
 
-/*
- * Cope with a missing in6addr_any and in6addr_loopback.
- */
 #if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY)
 extern const struct in6_addr isc_net_in6addrany;
+/*%
+ * Cope with a missing in6addr_any and in6addr_loopback.
+ */
 #define in6addr_any isc_net_in6addrany
 #endif
 
@@ -190,11 +200,12 @@ extern const struct in6_addr isc_net_in6addrloop;
 #define in6addr_loopback isc_net_in6addrloop
 #endif
 
-/*
- * Fix UnixWare 7.1.1's broken IN6_IS_ADDR_* definitions.
- */
 #ifdef ISC_PLATFORM_FIXIN6ISADDR
 #undef  IN6_IS_ADDR_GEOGRAPHIC
+/*!
+ * \brief
+ * Fix UnixWare 7.1.1's broken IN6_IS_ADDR_* definitions.
+ */
 #define IN6_IS_ADDR_GEOGRAPHIC(a) (((a)->S6_un.S6_l[0] & 0xE0) == 0x80)
 #undef  IN6_IS_ADDR_IPX
 #define IN6_IS_ADDR_IPX(a)        (((a)->S6_un.S6_l[0] & 0xFE) == 0x04)
@@ -210,24 +221,26 @@ extern const struct in6_addr isc_net_in6addrloop;
 #define IN6_IS_ADDR_SITELOCAL(a)  (((a)->S6_un.S6_l[0] & 0xC0FF) == 0xC0FE)
 #endif /* ISC_PLATFORM_FIXIN6ISADDR */
 
-/*
+#ifdef ISC_PLATFORM_NEEDPORTT
+/*%
  * Ensure type in_port_t is defined.
  */
-#ifdef ISC_PLATFORM_NEEDPORTT
 typedef isc_uint16_t in_port_t;
 #endif
 
-/*
+#ifndef MSG_TRUNC
+/*%
  * If this system does not have MSG_TRUNC (as returned from recvmsg())
  * ISC_PLATFORM_RECVOVERFLOW will be defined.  This will enable the MSG_TRUNC
  * faking code in socket.c.
  */
-#ifndef MSG_TRUNC
 #define ISC_PLATFORM_RECVOVERFLOW
 #endif
 
+/*% IP address. */
 #define ISC__IPADDR(x) ((isc_uint32_t)htonl((isc_uint32_t)(x)))
 
+/*% Is IP address multicast? */
 #define ISC_IPADDR_ISMULTICAST(i) \
                (((isc_uint32_t)(i) & ISC__IPADDR(0xf0000000)) \
                 == ISC__IPADDR(0xe0000000))
@@ -244,40 +257,40 @@ ISC_LANG_BEGINDECLS
 
 isc_result_t
 isc_net_probeipv4(void);
-/*
+/*%<
  * Check if the system's kernel supports IPv4.
  *
  * Returns:
  *
- *     ISC_R_SUCCESS           IPv4 is supported.
- *     ISC_R_NOTFOUND          IPv4 is not supported.
- *     ISC_R_DISABLED          IPv4 is disabled.
- *     ISC_R_UNEXPECTED
+ *\li  #ISC_R_SUCCESS          IPv4 is supported.
+ *\li  #ISC_R_NOTFOUND         IPv4 is not supported.
+ *\li  #ISC_R_DISABLED         IPv4 is disabled.
+ *\li  #ISC_R_UNEXPECTED
  */
 
 isc_result_t
 isc_net_probeipv6(void);
-/*
+/*%<
  * Check if the system's kernel supports IPv6.
  *
  * Returns:
  *
- *     ISC_R_SUCCESS           IPv6 is supported.
- *     ISC_R_NOTFOUND          IPv6 is not supported.
- *     ISC_R_DISABLED          IPv6 is disabled.
- *     ISC_R_UNEXPECTED
+ *\li  #ISC_R_SUCCESS          IPv6 is supported.
+ *\li  #ISC_R_NOTFOUND         IPv6 is not supported.
+ *\li  #ISC_R_DISABLED         IPv6 is disabled.
+ *\li  #ISC_R_UNEXPECTED
  */
 
 isc_result_t
 isc_net_probe_ipv6only(void);
-/*
+/*%<
  * Check if the system's kernel supports the IPV6_V6ONLY socket option.
  *
  * Returns:
  *
- *     ISC_R_SUCCESS           the option is supported for both TCP and UDP.
- *     ISC_R_NOTFOUND          IPv6 itself or the option is not supported.
- *     ISC_R_UNEXPECTED
+ *\li  #ISC_R_SUCCESS          the option is supported for both TCP and UDP.
+ *\li  #ISC_R_NOTFOUND         IPv6 itself or the option is not supported.
+ *\li  #ISC_R_UNEXPECTED
  */
 
 isc_result_t
@@ -288,9 +301,9 @@ isc_net_probe_ipv6pktinfo(void);
  *
  * Returns:
  *
- *     ISC_R_SUCCESS           the option is supported.
- *     ISC_R_NOTFOUND          IPv6 itself or the option is not supported.
- *     ISC_R_UNEXPECTED
+ * \li #ISC_R_SUCCESS          the option is supported.
+ * \li #ISC_R_NOTFOUND         IPv6 itself or the option is not supported.
+ * \li #ISC_R_UNEXPECTED
  */
 
 void
@@ -305,6 +318,29 @@ isc_net_enableipv4(void);
 void
 isc_net_enableipv6(void);
 
+isc_result_t
+isc_net_probeunix(void);
+/*
+ * Returns whether UNIX domain sockets are supported.
+ */
+
+isc_result_t
+isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high);
+/*%<
+ * Returns system's default range of ephemeral UDP ports, if defined.
+ * If the range is not available or unknown, ISC_NET_PORTRANGELOW and
+ * ISC_NET_PORTRANGEHIGH will be returned.
+ *
+ * Requires:
+ *
+ *\li  'low' and 'high' must be non NULL.
+ *
+ * Returns:
+ *
+ *\li  *low and *high will be the ports specifying the low and high ends of
+ *     the range.
+ */
+
 #ifdef ISC_PLATFORM_NEEDNTOP
 const char *
 isc_net_ntop(int af, const void *src, char *dst, size_t size);
@@ -318,11 +354,10 @@ isc_net_pton(int af, const char *src, void *dst);
 #define inet_pton isc_net_pton
 #endif
 
-#ifdef ISC_PLATFORM_NEEDATON
 int
 isc_net_aton(const char *cp, struct in_addr *addr);
+#undef inet_aton
 #define inet_aton isc_net_aton
-#endif
 
 ISC_LANG_ENDDECLS
 
diff --git a/lib/isc/unix/include/isc/netdb.h b/lib/isc/unix/include/isc/netdb.h
new file mode 100644 (file)
index 0000000..ff12a26
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: netdb.h,v 1.11 2007/06/19 23:47:19 tbox Exp $ */
+
+#ifndef ISC_NETDB_H
+#define ISC_NETDB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * Portable netdb.h support.
+ *
+ * This module is responsible for defining the get<x>by<y> APIs.
+ *
+ * MP:
+ *\li  No impact.
+ *
+ * Reliability:
+ *\li  No anticipated impact.
+ *
+ * Resources:
+ *\li  N/A.
+ *
+ * Security:
+ *\li  No anticipated impact.
+ *
+ * Standards:
+ *\li  BSD API
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/net.h>
+
+#include <netdb.h>
+
+#endif /* ISC_NETDB_H */
index 709bde4e07be2847931228e8a0c5b3ce9420306b..0e484becddf6bd9724f51045b30c1f67e1dbd52a 100644 (file)
@@ -1,34 +1,36 @@
 /*
+ * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2000, 2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: offset.h,v 1.10 2001/01/09 21:58:43 bwelling Exp $ */
+/* $Id: offset.h,v 1.15.332.2 2009/02/16 23:47:15 tbox Exp $ */
 
 #ifndef ISC_OFFSET_H
 #define ISC_OFFSET_H 1
 
-/*
+/*! \file
+ * \brief
  * File offsets are operating-system dependent.
  */
 #include <limits.h>             /* Required for CHAR_BIT. */
 #include <sys/types.h>
+#include <stddef.h>            /* For Linux Standard Base. */
 
 typedef off_t isc_offset_t;
 
-/*
+/*%
  * POSIX says "Additionally, blkcnt_t and off_t are extended signed integral
  * types", so the maximum value is all 1s except for the high bit.
  * This definition is more complex than it really needs to be because it was
index d1b24891968e84aa888f816f9ef2505c9782c764..b7a798649225254571088bbcf22b4ff9145f6945 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: stat.h,v 1.2.18.1 2004/08/19 04:42:54 marka Exp $ */
+/* $Id: stat.h,v 1.5 2007/06/19 23:47:19 tbox Exp $ */
 
 #ifndef ISC_STAT_H
 #define ISC_STAT_H 1
diff --git a/lib/isc/unix/include/isc/stdtime.h b/lib/isc/unix/include/isc/stdtime.h
new file mode 100644 (file)
index 0000000..4cb9e81
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stdtime.h,v 1.14 2007/06/19 23:47:19 tbox Exp $ */
+
+#ifndef ISC_STDTIME_H
+#define ISC_STDTIME_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/int.h>
+
+/*%
+ * It's public information that 'isc_stdtime_t' is an unsigned integral type.
+ * Applications that want maximum portability should not assume anything
+ * about its size.
+ */
+typedef isc_uint32_t isc_stdtime_t;
+/*
+ * isc_stdtime32_t is a 32-bit version of isc_stdtime_t.  A variable of this
+ * type should only be used as an opaque integer (e.g.,) to compare two
+ * time values.
+ */
+typedef isc_uint32_t isc_stdtime32_t;
+
+ISC_LANG_BEGINDECLS
+/* */
+void
+isc_stdtime_get(isc_stdtime_t *t);
+/*%<
+ * Set 't' to the number of seconds since 00:00:00 UTC, January 1, 1970.
+ *
+ * Requires:
+ *
+ *\li  't' is a valid pointer.
+ */
+
+#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
+/*
+ * Convert the standard time to its 32-bit version.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STDTIME_H */
index ca428af9553f996af955333f06e3ebcd91edb8dd..2953f71c6dacf53f26508b0cafbe19e5cf12df84 100644 (file)
@@ -1,35 +1,38 @@
 /*
+ * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: strerror.h,v 1.3 2001/11/20 01:45:47 gson Exp $ */
+/* $Id: strerror.h,v 1.8.332.2 2009/02/16 23:47:15 tbox Exp $ */
 
 #ifndef ISC_STRERROR_H
 #define ISC_STRERROR_H
 
+/*! \file */
+
 #include <sys/types.h>
 
 #include <isc/lang.h>
 
 ISC_LANG_BEGINDECLS
 
+/*% String Error Size */
 #define ISC_STRERRORSIZE 128
 
-/*
- * Provide a thread safe wrapper to strerrror().
+/*%
+ * Provide a thread safe wrapper to strerror().
  *
  * Requires:
  *     'buf' to be non NULL.
diff --git a/lib/isc/unix/include/isc/syslog.h b/lib/isc/unix/include/isc/syslog.h
new file mode 100644 (file)
index 0000000..7e0c88c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: syslog.h,v 1.7 2007/06/19 23:47:19 tbox Exp $ */
+
+#ifndef ISC_SYSLOG_H
+#define ISC_SYSLOG_H 1
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp);
+/*%<
+ * Convert 'str' to the appropriate syslog facility constant.
+ *
+ * Requires:
+ *
+ *\li  'str' is not NULL
+ *\li  'facilityp' is not NULL
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SYSLOG_H */
index 65794392a7eafac3678f404457ff27a94c707b18..45c4510e7603c5368ce523c34379d26d65be2185 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: time.h,v 1.30.18.2 2005/04/29 00:17:10 marka Exp $ */
+/* $Id: time.h,v 1.38.56.2 2009/01/05 23:47:23 tbox Exp $ */
 
 #ifndef ISC_TIME_H
 #define ISC_TIME_H 1
@@ -29,7 +29,7 @@
  *** Intervals
  ***/
 
-/*! 
+/*!
  *  \brief
  * The contents of this structure are private, and MUST NOT be accessed
  * directly by callers.
@@ -90,15 +90,17 @@ extern isc_time_t *isc_time_epoch;
 void
 isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds);
 /*%<
- * Set 't' to a particular number of seconds + nanoseconds since the epoch.
+ * Set 't' to a value which represents the given number of seconds and
+ * nanoseconds since 00:00:00 January 1, 1970, UTC.
  *
  * Notes:
- *\li  This call is equivalent to:
+ *\li  The Unix version of this call is equivalent to:
  *\code
  *     isc_time_settoepoch(t);
  *     isc_interval_set(i, seconds, nanoseconds);
  *     isc_time_add(t, i, t);
  *\endcode
+ *
  * Requires:
  *\li  't' is a valid pointer.
  *\li  nanoseconds < 1000000000.
@@ -110,7 +112,7 @@ isc_time_settoepoch(isc_time_t *t);
  * Set 't' to the time of the epoch.
  *
  * Notes:
- * \li The date of the epoch is platform-dependent.
+ *\li  The date of the epoch is platform-dependent.
  *
  * Requires:
  *
@@ -199,7 +201,7 @@ isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result);
  *\li  't', 'i', and 'result' are valid pointers.
  *
  * Returns:
- * \li Success
+ *\li  Success
  *\li  Out of range
  *             The interval added to the time is too large to
  *             be represented in the current definition of isc_time_t.
@@ -274,7 +276,7 @@ isc_time_nanoseconds(const isc_time_t *t);
  * Return the number of nanoseconds stored in a time structure.
  *
  * Notes:
- *\li  This is the number of nanoseconds in excess of the the number
+ *\li  This is the number of nanoseconds in excess of the number
  *     of seconds since the epoch; it will always be less than one
  *     full second.
  *
@@ -295,7 +297,35 @@ isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len);
  *
  *  Requires:
  *\li      'len' > 0
- *  \li    'buf' points to an array of at least len chars
+ *\li      'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ *  Requires:
+ *\li      'len' > 0
+ *\li      'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ssZ"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ *  Requires:
+ *\li      'len' > 0
+ *\li      'buf' points to an array of at least len chars
  *
  */
 
index 7e31975200c3e74e13d5d2c9732c69c9ba2f7ba6..4cfc82179e68d8712d95fe9b50f2f9635223a2fc 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: interfaceiter.c,v 1.22.2.1.10.14 2004/08/28 06:25:22 marka Exp $ */
+/* $Id: interfaceiter.c,v 1.44.120.2 2009/02/16 23:47:15 tbox Exp $ */
 
-#include <config.h>
+/*! \file */
 
-#define ISC_ONLY_IPV6
+#include <config.h>
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -33,6 +33,7 @@
 #include <errno.h>
 
 #include <isc/interfaceiter.h>
+#include <isc/log.h>
 #include <isc/magic.h>
 #include <isc/mem.h>
 #include <isc/msgs.h>
 #ifdef HAVE_NET_IF6_H
 #include <net/if6.h>
 #endif
+#include <net/if.h>
 
 /* Common utility functions */
 
-/*
+/*%
  * Extract the network address part from a "struct sockaddr".
- *
+ * \brief
  * The address family is given explicitly
  * instead of using src->sa_family, because the latter does not work
  * for copying a network mask obtained by SIOCGIFNETMASK (it does
@@ -143,6 +145,14 @@ get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
  * Include system-dependent code.
  */
 
+#ifdef __linux
+#define ISC_IF_INET6_SZ \
+    sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
+static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *);
+static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *);
+static void linux_if_inet6_first(isc_interfaceiter_t *iter);
+#endif
+
 #if HAVE_GETIFADDRS
 #include "ifiter_getifaddrs.c"
 #elif HAVE_IFLIST_SYSCTL
@@ -151,6 +161,88 @@ get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
 #include "ifiter_ioctl.c"
 #endif
 
+#ifdef __linux
+static void
+linux_if_inet6_first(isc_interfaceiter_t *iter) {
+       if (iter->proc != NULL) {
+               rewind(iter->proc);
+               (void)linux_if_inet6_next(iter);
+       } else
+               iter->valid = ISC_R_NOMORE;
+}
+
+static isc_result_t
+linux_if_inet6_next(isc_interfaceiter_t *iter) {
+       if (iter->proc != NULL &&
+           fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
+               iter->valid = ISC_R_SUCCESS;
+       else
+               iter->valid = ISC_R_NOMORE;
+       return (iter->valid);
+}
+
+static isc_result_t
+linux_if_inet6_current(isc_interfaceiter_t *iter) {
+       char address[33];
+       char name[IF_NAMESIZE+1];
+       struct in6_addr addr6;
+       int ifindex, prefix, flag3, flag4;
+       int res;
+       unsigned int i;
+
+       if (iter->valid != ISC_R_SUCCESS)
+               return (iter->valid);
+       if (iter->proc == NULL) {
+               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                             ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
+                             "/proc/net/if_inet6:iter->proc == NULL");
+               return (ISC_R_FAILURE);
+       }
+
+       res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
+                    address, &ifindex, &prefix, &flag3, &flag4, name);
+       if (res != 6) {
+               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                             ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
+                             "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
+                             res);
+               return (ISC_R_FAILURE);
+       }
+       if (strlen(address) != 32) {
+               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                             ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
+                             "/proc/net/if_inet6:strlen(%s) != 32", address);
+               return (ISC_R_FAILURE);
+       }
+       for (i = 0; i < 16; i++) {
+               unsigned char byte;
+               static const char hex[] = "0123456789abcdef";
+               byte = ((strchr(hex, address[i * 2]) - hex) << 4) |
+                      (strchr(hex, address[i * 2 + 1]) - hex);
+               addr6.s6_addr[i] = byte;
+       }
+       iter->current.af = AF_INET6;
+       iter->current.flags = INTERFACE_F_UP;
+       isc_netaddr_fromin6(&iter->current.address, &addr6);
+       if (isc_netaddr_islinklocal(&iter->current.address)) {
+               isc_netaddr_setzone(&iter->current.address,
+                                   (isc_uint32_t)ifindex);
+       }
+       for (i = 0; i < 16; i++) {
+               if (prefix > 8) {
+                       addr6.s6_addr[i] = 0xff;
+                       prefix -= 8;
+               } else {
+                       addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
+                       prefix = 0;
+               }
+       }
+       isc_netaddr_fromin6(&iter->current.netmask, &addr6);
+       strncpy(iter->current.name, name, sizeof(iter->current.name));
+       return (ISC_R_SUCCESS);
+}
+#endif
+
 /*
  * The remaining code is common to the sysctl and ioctl case.
  */
diff --git a/lib/isc/unix/ipv6.c b/lib/isc/unix/ipv6.c
new file mode 100644 (file)
index 0000000..61e984f
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ipv6.c,v 1.14 2007/06/19 23:47:18 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/ipv6.h>
+
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
diff --git a/lib/isc/unix/keyboard.c b/lib/isc/unix/keyboard.c
new file mode 100644 (file)
index 0000000..8ee62d3
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: keyboard.c,v 1.13 2007/06/19 23:47:18 tbox Exp $ */
+
+#include <config.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <isc/keyboard.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard) {
+       int fd;
+       isc_result_t ret;
+       struct termios current_mode;
+
+       REQUIRE(keyboard != NULL);
+
+       fd = open("/dev/tty", O_RDONLY, 0);
+       if (fd < 0)
+               return (ISC_R_IOERROR);
+
+       keyboard->fd = fd;
+
+       if (tcgetattr(fd, &keyboard->saved_mode) < 0) {
+               ret = ISC_R_IOERROR;
+               goto errout;
+       }
+
+       current_mode = keyboard->saved_mode;
+
+       current_mode.c_iflag &=
+                       ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+       current_mode.c_oflag &= ~OPOST;
+       current_mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+       current_mode.c_cflag &= ~(CSIZE|PARENB);
+       current_mode.c_cflag |= CS8;
+
+       current_mode.c_cc[VMIN] = 1;
+       current_mode.c_cc[VTIME] = 0;
+       if (tcsetattr(fd, TCSAFLUSH, &current_mode) < 0) {
+               ret = ISC_R_IOERROR;
+               goto errout;
+       }
+
+       keyboard->result = ISC_R_SUCCESS;
+
+       return (ISC_R_SUCCESS);
+
+ errout:
+       close (fd);
+
+       return (ret);
+}
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleeptime) {
+       REQUIRE(keyboard != NULL);
+
+       if (sleeptime > 0 && keyboard->result != ISC_R_CANCELED)
+               (void)sleep(sleeptime);
+
+       (void)tcsetattr(keyboard->fd, TCSAFLUSH, &keyboard->saved_mode);
+       (void)close(keyboard->fd);
+
+       keyboard->fd = -1;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp) {
+       ssize_t cc;
+       unsigned char c;
+       cc_t *controlchars;
+
+       REQUIRE(keyboard != NULL);
+       REQUIRE(cp != NULL);
+
+       cc = read(keyboard->fd, &c, 1);
+       if (cc < 0) {
+               keyboard->result = ISC_R_IOERROR;
+               return (keyboard->result);
+       }
+
+       controlchars = keyboard->saved_mode.c_cc;
+       if (c == controlchars[VINTR] || c == controlchars[VQUIT]) {
+               keyboard->result = ISC_R_CANCELED;
+               return (keyboard->result);
+       }
+
+       *cp = c;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_boolean_t
+isc_keyboard_canceled(isc_keyboard_t *keyboard) {
+       return (ISC_TF(keyboard->result == ISC_R_CANCELED));
+}
index 3d4ab66e7123eb9558c8741e206ebbf3f9a6e4eb..b2fb30e4ed99620ba59664199a22b888facf70ee 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: net.c,v 1.22.2.2.10.7 2004/04/29 01:31:22 marka Exp $ */
+/* $Id: net.c,v 1.40 2008/07/04 05:52:31 each Exp $ */
 
 #include <config.h>
 
+#include <sys/types.h>
+
+#if defined(HAVE_SYS_SYSCTL_H)
+#if defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#endif
+#include <sys/sysctl.h>
+#endif
+
 #include <errno.h>
 #include <unistd.h>
 
+#include <isc/log.h>
+#include <isc/msgs.h>
 #include <isc/net.h>
 #include <isc/once.h>
 #include <isc/strerror.h>
 #include <isc/string.h>
 #include <isc/util.h>
 
-#if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY)
-const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
+/*%
+ * Definitions about UDP port range specification.  This is a total mess of
+ * portability variants: some use sysctl (but the sysctl names vary), some use
+ * system-specific interfaces, some have the same interface for IPv4 and IPv6,
+ * some separate them, etc...
+ */
+
+/*%
+ * The last resort defaults: use all non well known port space
+ */
+#ifndef ISC_NET_PORTRANGELOW
+#define ISC_NET_PORTRANGELOW 1024
+#endif /* ISC_NET_PORTRANGELOW */
+#ifndef ISC_NET_PORTRANGEHIGH
+#define ISC_NET_PORTRANGEHIGH 65535
+#endif /* ISC_NET_PORTRANGEHIGH */
+
+#ifdef HAVE_SYSCTLBYNAME
+
+/*%
+ * sysctl variants
+ */
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
+#define USE_SYSCTL_PORTRANGE
+#define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
+#define SYSCTL_V4PORTRANGE_HIGH        "net.inet.ip.portrange.hilast"
+#define SYSCTL_V6PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
+#define SYSCTL_V6PORTRANGE_HIGH        "net.inet.ip.portrange.hilast"
 #endif
 
-#if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
-const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
+#ifdef __NetBSD__
+#define USE_SYSCTL_PORTRANGE
+#define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.anonportmin"
+#define SYSCTL_V4PORTRANGE_HIGH        "net.inet.ip.anonportmax"
+#define SYSCTL_V6PORTRANGE_LOW "net.inet6.ip6.anonportmin"
+#define SYSCTL_V6PORTRANGE_HIGH        "net.inet6.ip6.anonportmax"
 #endif
 
-static isc_boolean_t   once = ISC_FALSE;
+#else /* !HAVE_SYSCTLBYNAME */
+
+#ifdef __OpenBSD__
+#define USE_SYSCTL_PORTRANGE
+#define SYSCTL_V4PORTRANGE_LOW { CTL_NET, PF_INET, IPPROTO_IP, \
+                                 IPCTL_IPPORT_HIFIRSTAUTO }
+#define SYSCTL_V4PORTRANGE_HIGH        { CTL_NET, PF_INET, IPPROTO_IP, \
+                                 IPCTL_IPPORT_HILASTAUTO }
+/* Same for IPv6 */
+#define SYSCTL_V6PORTRANGE_LOW SYSCTL_V4PORTRANGE_LOW
+#define SYSCTL_V6PORTRANGE_HIGH        SYSCTL_V4PORTRANGE_HIGH
+#endif
+
+#endif /* HAVE_SYSCTLBYNAME */
+
+#if defined(ISC_PLATFORM_HAVEIPV6)
+# if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
+const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
+# endif
+
+# if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
+const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
+# endif
+
+# if defined(WANT_IPV6)
 static isc_once_t      once_ipv6only = ISC_ONCE_INIT;
+# endif
+
+# if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
 static isc_once_t      once_ipv6pktinfo = ISC_ONCE_INIT;
+# endif
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+
+static isc_once_t      once = ISC_ONCE_INIT;
+
 static isc_result_t    ipv4_result = ISC_R_NOTFOUND;
 static isc_result_t    ipv6_result = ISC_R_NOTFOUND;
+static isc_result_t    unix_result = ISC_R_NOTFOUND;
 static isc_result_t    ipv6only_result = ISC_R_NOTFOUND;
 static isc_result_t    ipv6pktinfo_result = ISC_R_NOTFOUND;
 
@@ -66,7 +140,11 @@ try_proto(int domain) {
                default:
                        isc__strerror(errno, strbuf, sizeof(strbuf));
                        UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                        "socket() failed: %s",
+                                        "socket() %s: %s",
+                                        isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_GENERAL,
+                                                       ISC_MSG_FAILED,
+                                                       "failed"),
                                         strbuf);
                        return (ISC_R_UNEXPECTED);
                }
@@ -77,19 +155,37 @@ try_proto(int domain) {
 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
        if (domain == PF_INET6) {
                struct sockaddr_in6 sin6;
-               GETSOCKNAME_SOCKLEN_TYPE len;
+               unsigned int len;
 
                /*
                 * Check to see if IPv6 is broken, as is common on Linux.
                 */
                len = sizeof(sin6);
-               if (getsockname(s, (struct sockaddr *)&sin6, &len) < 0)
+               if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
                {
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                                     "retrieving the address of an IPv6 "
+                                     "socket from the kernel failed.");
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                                     "IPv6 is not supported.");
                        result = ISC_R_NOTFOUND;
                } else {
                        if (len == sizeof(struct sockaddr_in6))
                                result = ISC_R_SUCCESS;
                        else {
+                               isc_log_write(isc_lctx,
+                                             ISC_LOGCATEGORY_GENERAL,
+                                             ISC_LOGMODULE_SOCKET,
+                                             ISC_LOG_ERROR,
+                                             "IPv6 structures in kernel and "
+                                             "user space do not match.");
+                               isc_log_write(isc_lctx,
+                                             ISC_LOGCATEGORY_GENERAL,
+                                             ISC_LOGMODULE_SOCKET,
+                                             ISC_LOG_ERROR,
+                                             "IPv6 is not supported.");
                                result = ISC_R_NOTFOUND;
                        }
                }
@@ -113,14 +209,14 @@ initialize_action(void) {
 #endif
 #endif
 #endif
+#ifdef ISC_PLATFORM_HAVESYSUNH
+       unix_result = try_proto(PF_UNIX);
+#endif
 }
 
 static void
 initialize(void) {
-       if(once == ISC_FALSE) {
-               initialize_action();
-               once = ISC_TRUE;
-       }
+       RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
 }
 
 isc_result_t
@@ -135,6 +231,12 @@ isc_net_probeipv6(void) {
        return (ipv6_result);
 }
 
+isc_result_t
+isc_net_probeunix(void) {
+       initialize();
+       return (unix_result);
+}
+
 #ifdef ISC_PLATFORM_HAVEIPV6
 #ifdef WANT_IPV6
 static void
@@ -160,7 +262,11 @@ try_ipv6only(void) {
        if (s == -1) {
                isc__strerror(errno, strbuf, sizeof(strbuf));
                UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                "socket() failed: %s",
+                                "socket() %s: %s",
+                                isc_msgcat_get(isc_msgcat,
+                                               ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED,
+                                               "failed"),
                                 strbuf);
                ipv6only_result = ISC_R_UNEXPECTED;
                return;
@@ -179,7 +285,11 @@ try_ipv6only(void) {
        if (s == -1) {
                isc__strerror(errno, strbuf, sizeof(strbuf));
                UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                "socket() failed: %s",
+                                "socket() %s: %s",
+                                isc_msgcat_get(isc_msgcat,
+                                               ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED,
+                                               "failed"),
                                 strbuf);
                ipv6only_result = ISC_R_UNEXPECTED;
                return;
@@ -206,7 +316,9 @@ initialize_ipv6only(void) {
        RUNTIME_CHECK(isc_once_do(&once_ipv6only,
                                  try_ipv6only) == ISC_R_SUCCESS);
 }
+#endif /* WANT_IPV6 */
 
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
 static void
 try_ipv6pktinfo(void) {
        int s, on;
@@ -225,7 +337,11 @@ try_ipv6pktinfo(void) {
        if (s == -1) {
                isc__strerror(errno, strbuf, sizeof(strbuf));
                UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                "socket() failed: %s",
+                                "socket() %s: %s",
+                                isc_msgcat_get(isc_msgcat,
+                                               ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED,
+                                               "failed"),
                                 strbuf);
                ipv6pktinfo_result = ISC_R_UNEXPECTED;
                return;
@@ -255,7 +371,7 @@ initialize_ipv6pktinfo(void) {
        RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
                                  try_ipv6pktinfo) == ISC_R_SUCCESS);
 }
-#endif /* WANT_IPV6 */
+#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
 #endif /* ISC_PLATFORM_HAVEIPV6 */
 
 isc_result_t
@@ -273,15 +389,112 @@ isc_net_probe_ipv6only(void) {
 isc_result_t
 isc_net_probe_ipv6pktinfo(void) {
 #ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
 #ifdef WANT_IPV6
        initialize_ipv6pktinfo();
 #else
        ipv6pktinfo_result = ISC_R_NOTFOUND;
 #endif
+#endif
 #endif
        return (ipv6pktinfo_result);
 }
 
+#if defined(USE_SYSCTL_PORTRANGE)
+#if defined(HAVE_SYSCTLBYNAME)
+static isc_result_t
+getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
+       int port_low, port_high;
+       size_t portlen;
+       const char *sysctlname_lowport, *sysctlname_hiport;
+
+       if (af == AF_INET) {
+               sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
+               sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
+       } else {
+               sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
+               sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
+       }
+       portlen = sizeof(portlen);
+       if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
+                        NULL, 0) < 0) {
+               return (ISC_R_FAILURE);
+       }
+       portlen = sizeof(portlen);
+       if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
+                        NULL, 0) < 0) {
+               return (ISC_R_FAILURE);
+       }
+       if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
+               return (ISC_R_RANGE);
+
+       *low = (in_port_t)port_low;
+       *high = (in_port_t)port_high;
+
+       return (ISC_R_SUCCESS);
+}
+#else /* !HAVE_SYSCTLBYNAME */
+static isc_result_t
+getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
+       int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
+       int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
+       int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
+       int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
+       int *mib_lo, *mib_hi, miblen;
+       int port_low, port_high;
+       size_t portlen;
+
+       if (af == AF_INET) {
+               mib_lo = mib_lo4;
+               mib_hi = mib_hi4;
+               miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
+       } else {
+               mib_lo = mib_lo6;
+               mib_hi = mib_hi6;
+               miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
+       }
+
+       portlen = sizeof(portlen);
+       if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
+               return (ISC_R_FAILURE);
+       }
+
+       portlen = sizeof(portlen);
+       if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
+               return (ISC_R_FAILURE);
+       }
+
+       if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
+               return (ISC_R_RANGE);
+
+       *low = (in_port_t) port_low;
+       *high = (in_port_t) port_high;
+
+       return (ISC_R_SUCCESS);
+}
+#endif /* HAVE_SYSCTLBYNAME */
+#endif /* USE_SYSCTL_PORTRANGE */
+
+isc_result_t
+isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
+       int result = ISC_R_FAILURE;
+
+       REQUIRE(low != NULL && high != NULL);
+
+#if defined(USE_SYSCTL_PORTRANGE)
+       result = getudpportrange_sysctl(af, low, high);
+#else
+       UNUSED(af);
+#endif
+
+       if (result != ISC_R_SUCCESS) {
+               *low = ISC_NET_PORTRANGELOW;
+               *high = ISC_NET_PORTRANGEHIGH;
+       }
+
+       return (ISC_R_SUCCESS); /* we currently never fail in this function */
+}
+
 void
 isc_net_disableipv4(void) {
        initialize();
diff --git a/lib/isc/unix/os.c b/lib/isc/unix/os.c
new file mode 100644 (file)
index 0000000..c050d14
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: os.c,v 1.18 2007/06/19 23:47:18 tbox Exp $ */
+
+#include <config.h>
+
+#include <isc/os.h>
+
+
+#ifdef HAVE_SYSCONF
+
+#include <unistd.h>
+
+#ifndef __hpux
+static inline long
+sysconf_ncpus(void) {
+#if defined(_SC_NPROCESSORS_ONLN)
+       return sysconf((_SC_NPROCESSORS_ONLN));
+#elif defined(_SC_NPROC_ONLN)
+       return sysconf((_SC_NPROC_ONLN));
+#else
+       return (0);
+#endif
+}
+#endif
+#endif /* HAVE_SYSCONF */
+
+
+#ifdef __hpux
+
+#include <sys/pstat.h>
+
+static inline int
+hpux_ncpus(void) {
+       struct pst_dynamic psd;
+       if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) != -1)
+               return (psd.psd_proc_cnt);
+       else
+               return (0);
+}
+
+#endif /* __hpux */
+
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)
+#include <sys/types.h>  /* for FreeBSD */
+#include <sys/param.h>  /* for NetBSD */
+#include <sys/sysctl.h>
+
+static int
+sysctl_ncpus(void) {
+       int ncpu, result;
+       size_t len;
+
+       len = sizeof(ncpu);
+       result = sysctlbyname("hw.ncpu", &ncpu, &len , 0, 0);
+       if (result != -1)
+               return (ncpu);
+       return (0);
+}
+#endif
+
+unsigned int
+isc_os_ncpus(void) {
+       long ncpus = 0;
+
+#ifdef __hpux
+       ncpus = hpux_ncpus();
+#elif defined(HAVE_SYSCONF)
+       ncpus = sysconf_ncpus();
+#endif
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)
+       if (ncpus <= 0)
+               ncpus = sysctl_ncpus();
+#endif
+       if (ncpus <= 0)
+               ncpus = 1;
+
+       return ((unsigned int)ncpus);
+}
diff --git a/lib/isc/unix/resource.c b/lib/isc/unix/resource.c
new file mode 100644 (file)
index 0000000..8bd8885
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2004, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: resource.c,v 1.21.66.2 2009/02/13 23:47:39 tbox Exp $ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/time.h>  /* Required on some systems for <sys/resource.h>. */
+#include <sys/resource.h>
+
+#include <isc/platform.h>
+#include <isc/resource.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#ifdef __linux__
+#include <linux/fs.h>  /* To get the large NR_OPEN. */
+#endif
+
+#if defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
+#include <sys/dyntune.h>
+#endif
+
+#include "errno2result.h"
+
+static isc_result_t
+resource2rlim(isc_resource_t resource, int *rlim_resource) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       switch (resource) {
+       case isc_resource_coresize:
+               *rlim_resource = RLIMIT_CORE;
+               break;
+       case isc_resource_cputime:
+               *rlim_resource = RLIMIT_CPU;
+               break;
+       case isc_resource_datasize:
+               *rlim_resource = RLIMIT_DATA;
+               break;
+       case isc_resource_filesize:
+               *rlim_resource = RLIMIT_FSIZE;
+               break;
+       case isc_resource_lockedmemory:
+#ifdef RLIMIT_MEMLOCK
+               *rlim_resource = RLIMIT_MEMLOCK;
+#else
+               result = ISC_R_NOTIMPLEMENTED;
+#endif
+               break;
+       case isc_resource_openfiles:
+#ifdef RLIMIT_NOFILE
+               *rlim_resource = RLIMIT_NOFILE;
+#else
+               result = ISC_R_NOTIMPLEMENTED;
+#endif
+               break;
+       case isc_resource_processes:
+#ifdef RLIMIT_NPROC
+               *rlim_resource = RLIMIT_NPROC;
+#else
+               result = ISC_R_NOTIMPLEMENTED;
+#endif
+               break;
+       case isc_resource_residentsize:
+#ifdef RLIMIT_RSS
+               *rlim_resource = RLIMIT_RSS;
+#else
+               result = ISC_R_NOTIMPLEMENTED;
+#endif
+               break;
+       case isc_resource_stacksize:
+               *rlim_resource = RLIMIT_STACK;
+               break;
+       default:
+               /*
+                * This test is not very robust if isc_resource_t
+                * changes, but generates a clear assertion message.
+                */
+               REQUIRE(resource >= isc_resource_coresize &&
+                       resource <= isc_resource_stacksize);
+
+               result = ISC_R_RANGE;
+               break;
+       }
+
+       return (result);
+}
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
+       struct rlimit rl;
+       ISC_PLATFORM_RLIMITTYPE rlim_value;
+       int unixresult;
+       int unixresource;
+       isc_result_t result;
+
+       result = resource2rlim(resource, &unixresource);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       if (value == ISC_RESOURCE_UNLIMITED)
+               rlim_value = RLIM_INFINITY;
+
+       else {
+               /*
+                * isc_resourcevalue_t was chosen as an unsigned 64 bit
+                * integer so that it could contain the maximum range of
+                * reasonable values.  Unfortunately, this exceeds the typical
+                * range on Unix systems.  Ensure the range of
+                * ISC_PLATFORM_RLIMITTYPE is not overflowed.
+                */
+               isc_resourcevalue_t rlim_max;
+               isc_boolean_t rlim_t_is_signed =
+                       ISC_TF(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0);
+
+               if (rlim_t_is_signed)
+                       rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 <<
+                                    (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1));
+               else
+                       rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1;
+
+               if (value > rlim_max)
+                       value = rlim_max;
+
+               rlim_value = value;
+       }
+
+       rl.rlim_cur = rl.rlim_max = rlim_value;
+       unixresult = setrlimit(unixresource, &rl);
+
+       if (unixresult == 0)
+               return (ISC_R_SUCCESS);
+
+#if defined(OPEN_MAX) && defined(__APPLE__)
+       /*
+        * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the
+        * maximum possible value is OPEN_MAX.  BIND8 used to use
+        * sysconf(_SC_OPEN_MAX) for such a case, but this value is much
+        * smaller than OPEN_MAX and is not really effective.
+        */
+       if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
+               rl.rlim_cur = OPEN_MAX;
+               unixresult = setrlimit(unixresource, &rl);
+               if (unixresult == 0)
+                       return (ISC_R_SUCCESS);
+       }
+#elif defined(__linux__)
+#ifndef NR_OPEN
+#define NR_OPEN (1024*1024)
+#endif
+
+       /*
+        * Some Linux kernels don't accept RLIM_INFINIT; the maximum
+        * possible value is the NR_OPEN defined in linux/fs.h.
+        */
+       if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
+               rl.rlim_cur = rl.rlim_max = NR_OPEN;
+               unixresult = setrlimit(unixresource, &rl);
+               if (unixresult == 0)
+                       return (ISC_R_SUCCESS);
+       }
+#elif defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
+       if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
+               uint64_t maxfiles;
+               if (gettune("maxfiles_lim", &maxfiles) == 0) {
+                       rl.rlim_cur = rl.rlim_max = maxfiles;
+                       unixresult = setrlimit(unixresource, &rl);
+                       if (unixresult == 0)
+                               return (ISC_R_SUCCESS);
+               }
+       }
+#endif
+       if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
+               if (getrlimit(unixresource, &rl) == 0) {
+                       rl.rlim_cur = rl.rlim_max;
+                       unixresult = setrlimit(unixresource, &rl);
+                       if (unixresult == 0)
+                               return (ISC_R_SUCCESS);
+               }
+       }
+       return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+       int unixresult;
+       int unixresource;
+       struct rlimit rl;
+       isc_result_t result;
+
+       result = resource2rlim(resource, &unixresource);
+       if (result == ISC_R_SUCCESS) {
+               unixresult = getrlimit(unixresource, &rl);
+               INSIST(unixresult == 0);
+               *value = rl.rlim_max;
+       }
+
+       return (result);
+}
+
+isc_result_t
+isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+       int unixresult;
+       int unixresource;
+       struct rlimit rl;
+       isc_result_t result;
+
+       result = resource2rlim(resource, &unixresource);
+       if (result == ISC_R_SUCCESS) {
+               unixresult = getrlimit(unixresource, &rl);
+               INSIST(unixresult == 0);
+               *value = rl.rlim_cur;
+       }
+
+       return (result);
+}
diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c
new file mode 100644 (file)
index 0000000..d09fe51
--- /dev/null
@@ -0,0 +1,5550 @@
+/*
+ * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: socket.c,v 1.308.12.8 2009/04/18 01:29:26 jinmei Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/buffer.h>
+#include <isc/bufferlist.h>
+#include <isc/condition.h>
+#include <isc/formatcheck.h>
+#include <isc/list.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/once.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/socket.h>
+#include <isc/stats.h>
+#include <isc/strerror.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+#include <isc/xml.h>
+
+#ifdef ISC_PLATFORM_HAVESYSUNH
+#include <sys/un.h>
+#endif
+#ifdef ISC_PLATFORM_HAVEKQUEUE
+#include <sys/event.h>
+#endif
+#ifdef ISC_PLATFORM_HAVEEPOLL
+#include <sys/epoll.h>
+#endif
+#ifdef ISC_PLATFORM_HAVEDEVPOLL
+#include <sys/devpoll.h>
+#endif
+
+#include "errno2result.h"
+
+#ifndef ISC_PLATFORM_USETHREADS
+#include "socket_p.h"
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#if defined(SO_BSDCOMPAT) && defined(__linux__)
+#include <sys/utsname.h>
+#endif
+
+/*%
+ * Choose the most preferable multiplex method.
+ */
+#ifdef ISC_PLATFORM_HAVEKQUEUE
+#define USE_KQUEUE
+#elif defined (ISC_PLATFORM_HAVEEPOLL)
+#define USE_EPOLL
+#elif defined (ISC_PLATFORM_HAVEDEVPOLL)
+#define USE_DEVPOLL
+typedef struct {
+       unsigned int want_read : 1,
+               want_write : 1;
+} pollinfo_t;
+#else
+#define USE_SELECT
+#endif /* ISC_PLATFORM_HAVEKQUEUE */
+
+#ifndef ISC_PLATFORM_USETHREADS
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+struct isc_socketwait {
+       int nevents;
+};
+#elif defined (USE_SELECT)
+struct isc_socketwait {
+       fd_set *readset;
+       fd_set *writeset;
+       int nfds;
+       int maxfd;
+};
+#endif /* USE_KQUEUE */
+#endif /* !ISC_PLATFORM_USETHREADS */
+
+/*%
+ * Maximum number of allowable open sockets.  This is also the maximum
+ * allowable socket file descriptor.
+ *
+ * Care should be taken before modifying this value for select():
+ * The API standard doesn't ensure select() accept more than (the system default
+ * of) FD_SETSIZE descriptors, and the default size should in fact be fine in
+ * the vast majority of cases.  This constant should therefore be increased only
+ * when absolutely necessary and possible, i.e., the server is exhausting all
+ * available file descriptors (up to FD_SETSIZE) and the select() function
+ * and FD_xxx macros support larger values than FD_SETSIZE (which may not
+ * always by true, but we keep using some of them to ensure as much
+ * portability as possible).  Note also that overall server performance
+ * may be rather worsened with a larger value of this constant due to
+ * inherent scalability problems of select().
+ *
+ * As a special note, this value shouldn't have to be touched if
+ * this is a build for an authoritative only DNS server.
+ */
+#ifndef ISC_SOCKET_MAXSOCKETS
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+#define ISC_SOCKET_MAXSOCKETS 4096
+#elif defined(USE_SELECT)
+#define ISC_SOCKET_MAXSOCKETS FD_SETSIZE
+#endif /* USE_KQUEUE... */
+#endif /* ISC_SOCKET_MAXSOCKETS */
+
+#ifdef USE_SELECT
+/*%
+ * Mac OS X needs a special definition to support larger values in select().
+ * We always define this because a larger value can be specified run-time.
+ */
+#ifdef __APPLE__
+#define _DARWIN_UNLIMITED_SELECT
+#endif /* __APPLE__ */
+#endif /* USE_SELECT */
+
+#ifdef ISC_SOCKET_USE_POLLWATCH
+/*%
+ * If this macro is defined, enable workaround for a Solaris /dev/poll kernel
+ * bug: DP_POLL ioctl could keep sleeping even if socket I/O is possible for
+ * some of the specified FD.  The idea is based on the observation that it's
+ * likely for a busy server to keep receiving packets.  It specifically works
+ * as follows: the socket watcher is first initialized with the state of
+ * "poll_idle".  While it's in the idle state it keeps sleeping until a socket
+ * event occurs.  When it wakes up for a socket I/O event, it moves to the
+ * poll_active state, and sets the poll timeout to a short period
+ * (ISC_SOCKET_POLLWATCH_TIMEOUT msec).  If timeout occurs in this state, the
+ * watcher goes to the poll_checking state with the same timeout period.
+ * In this state, the watcher tries to detect whether this is a break
+ * during intermittent events or the kernel bug is triggered.  If the next
+ * polling reports an event within the short period, the previous timeout is
+ * likely to be a kernel bug, and so the watcher goes back to the active state.
+ * Otherwise, it moves to the idle state again.
+ *
+ * It's not clear whether this is a thread-related bug, but since we've only
+ * seen this with threads, this workaround is used only when enabling threads.
+ */
+
+typedef enum { poll_idle, poll_active, poll_checking } pollstate_t;
+
+#ifndef ISC_SOCKET_POLLWATCH_TIMEOUT
+#define ISC_SOCKET_POLLWATCH_TIMEOUT 10
+#endif /* ISC_SOCKET_POLLWATCH_TIMEOUT */
+#endif /* ISC_SOCKET_USE_POLLWATCH */
+
+/*%
+ * Size of per-FD lock buckets.
+ */
+#ifdef ISC_PLATFORM_USETHREADS
+#define FDLOCK_COUNT           1024
+#define FDLOCK_ID(fd)          ((fd) % FDLOCK_COUNT)
+#else
+#define FDLOCK_COUNT           1
+#define FDLOCK_ID(fd)          0
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/*%
+ * Maximum number of events communicated with the kernel.  There should normally
+ * be no need for having a large number.
+ */
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+#ifndef ISC_SOCKET_MAXEVENTS
+#define ISC_SOCKET_MAXEVENTS   64
+#endif
+#endif
+
+/*%
+ * Some systems define the socket length argument as an int, some as size_t,
+ * some as socklen_t.  This is here so it can be easily changed if needed.
+ */
+#ifndef ISC_SOCKADDR_LEN_T
+#define ISC_SOCKADDR_LEN_T unsigned int
+#endif
+
+/*%
+ * Define what the possible "soft" errors can be.  These are non-fatal returns
+ * of various network related functions, like recv() and so on.
+ *
+ * For some reason, BSDI (and perhaps others) will sometimes return <0
+ * from recv() but will have errno==0.  This is broken, but we have to
+ * work around it here.
+ */
+#define SOFT_ERROR(e)  ((e) == EAGAIN || \
+                        (e) == EWOULDBLOCK || \
+                        (e) == EINTR || \
+                        (e) == 0)
+
+#define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x)
+
+/*!<
+ * DLVL(90)  --  Function entry/exit and other tracing.
+ * DLVL(70)  --  Socket "correctness" -- including returning of events, etc.
+ * DLVL(60)  --  Socket data send/receive
+ * DLVL(50)  --  Event tracing, including receiving/sending completion events.
+ * DLVL(20)  --  Socket creation/destruction.
+ */
+#define TRACE_LEVEL            90
+#define CORRECTNESS_LEVEL      70
+#define IOEVENT_LEVEL          60
+#define EVENT_LEVEL            50
+#define CREATION_LEVEL         20
+
+#define TRACE          DLVL(TRACE_LEVEL)
+#define CORRECTNESS    DLVL(CORRECTNESS_LEVEL)
+#define IOEVENT                DLVL(IOEVENT_LEVEL)
+#define EVENT          DLVL(EVENT_LEVEL)
+#define CREATION       DLVL(CREATION_LEVEL)
+
+typedef isc_event_t intev_t;
+
+#define SOCKET_MAGIC           ISC_MAGIC('I', 'O', 'i', 'o')
+#define VALID_SOCKET(t)                ISC_MAGIC_VALID(t, SOCKET_MAGIC)
+
+/*!
+ * IPv6 control information.  If the socket is an IPv6 socket we want
+ * to collect the destination address and interface so the client can
+ * set them on outgoing packets.
+ */
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+#ifndef USE_CMSG
+#define USE_CMSG       1
+#endif
+#endif
+
+/*%
+ * NetBSD and FreeBSD can timestamp packets.  XXXMLG Should we have
+ * a setsockopt() like interface to request timestamps, and if the OS
+ * doesn't do it for us, call gettimeofday() on every UDP receive?
+ */
+#ifdef SO_TIMESTAMP
+#ifndef USE_CMSG
+#define USE_CMSG       1
+#endif
+#endif
+
+/*%
+ * The size to raise the receive buffer to (from BIND 8).
+ */
+#define RCVBUFSIZE (32*1024)
+
+/*%
+ * The number of times a send operation is repeated if the result is EINTR.
+ */
+#define NRETRIES 10
+
+struct isc_socket {
+       /* Not locked. */
+       unsigned int            magic;
+       isc_socketmgr_t        *manager;
+       isc_mutex_t             lock;
+       isc_sockettype_t        type;
+       const isc_statscounter_t        *statsindex;
+
+       /* Locked by socket lock. */
+       ISC_LINK(isc_socket_t)  link;
+       unsigned int            references;
+       int                     fd;
+       int                     pf;
+       char                            name[16];
+       void *                          tag;
+
+       ISC_LIST(isc_socketevent_t)             send_list;
+       ISC_LIST(isc_socketevent_t)             recv_list;
+       ISC_LIST(isc_socket_newconnev_t)        accept_list;
+       isc_socket_connev_t                    *connect_ev;
+
+       /*
+        * Internal events.  Posted when a descriptor is readable or
+        * writable.  These are statically allocated and never freed.
+        * They will be set to non-purgable before use.
+        */
+       intev_t                 readable_ev;
+       intev_t                 writable_ev;
+
+       isc_sockaddr_t          peer_address;  /* remote address */
+
+       unsigned int            pending_recv : 1,
+                               pending_send : 1,
+                               pending_accept : 1,
+                               listener : 1, /* listener socket */
+                               connected : 1,
+                               connecting : 1, /* connect pending */
+                               bound : 1; /* bound to local addr */
+
+#ifdef ISC_NET_RECVOVERFLOW
+       unsigned char           overflow; /* used for MSG_TRUNC fake */
+#endif
+
+       char                    *recvcmsgbuf;
+       ISC_SOCKADDR_LEN_T      recvcmsgbuflen;
+       char                    *sendcmsgbuf;
+       ISC_SOCKADDR_LEN_T      sendcmsgbuflen;
+
+       void                    *fdwatcharg;
+       isc_sockfdwatch_t       fdwatchcb;
+       int                     fdwatchflags;
+       isc_task_t              *fdwatchtask;
+};
+
+#define SOCKET_MANAGER_MAGIC   ISC_MAGIC('I', 'O', 'm', 'g')
+#define VALID_MANAGER(m)       ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
+
+struct isc_socketmgr {
+       /* Not locked. */
+       unsigned int            magic;
+       isc_mem_t              *mctx;
+       isc_mutex_t             lock;
+       isc_mutex_t             *fdlock;
+       isc_stats_t             *stats;
+#ifdef USE_KQUEUE
+       int                     kqueue_fd;
+       int                     nevents;
+       struct kevent           *events;
+#endif /* USE_KQUEUE */
+#ifdef USE_EPOLL
+       int                     epoll_fd;
+       int                     nevents;
+       struct epoll_event      *events;
+#endif /* USE_EPOLL */
+#ifdef USE_DEVPOLL
+       int                     devpoll_fd;
+       int                     nevents;
+       struct pollfd           *events;
+#endif /* USE_DEVPOLL */
+#ifdef USE_SELECT
+       int                     fd_bufsize;
+#endif /* USE_SELECT */
+       unsigned int            maxsocks;
+#ifdef ISC_PLATFORM_USETHREADS
+       int                     pipe_fds[2];
+#endif
+
+       /* Locked by fdlock. */
+       isc_socket_t           **fds;
+       int                     *fdstate;
+#ifdef USE_DEVPOLL
+       pollinfo_t              *fdpollinfo;
+#endif
+
+       /* Locked by manager lock. */
+       ISC_LIST(isc_socket_t)  socklist;
+#ifdef USE_SELECT
+       fd_set                  *read_fds;
+       fd_set                  *read_fds_copy;
+       fd_set                  *write_fds;
+       fd_set                  *write_fds_copy;
+       int                     maxfd;
+#endif /* USE_SELECT */
+       int                     reserved;       /* unlocked */
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_thread_t            watcher;
+       isc_condition_t         shutdown_ok;
+#else /* ISC_PLATFORM_USETHREADS */
+       unsigned int            refs;
+#endif /* ISC_PLATFORM_USETHREADS */
+};
+
+#ifndef ISC_PLATFORM_USETHREADS
+static isc_socketmgr_t *socketmgr = NULL;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#define CLOSED                 0       /* this one must be zero */
+#define MANAGED                        1
+#define CLOSE_PENDING          2
+
+/*
+ * send() and recv() iovec counts
+ */
+#define MAXSCATTERGATHER_SEND  (ISC_SOCKET_MAXSCATTERGATHER)
+#ifdef ISC_NET_RECVOVERFLOW
+# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER + 1)
+#else
+# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
+#endif
+
+static void send_recvdone_event(isc_socket_t *, isc_socketevent_t **);
+static void send_senddone_event(isc_socket_t *, isc_socketevent_t **);
+static void free_socket(isc_socket_t **);
+static isc_result_t allocate_socket(isc_socketmgr_t *, isc_sockettype_t,
+                                   isc_socket_t **);
+static void destroy(isc_socket_t **);
+static void internal_accept(isc_task_t *, isc_event_t *);
+static void internal_connect(isc_task_t *, isc_event_t *);
+static void internal_recv(isc_task_t *, isc_event_t *);
+static void internal_send(isc_task_t *, isc_event_t *);
+static void internal_fdwatch_write(isc_task_t *, isc_event_t *);
+static void internal_fdwatch_read(isc_task_t *, isc_event_t *);
+static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
+static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
+                             struct msghdr *, struct iovec *, size_t *);
+static void build_msghdr_recv(isc_socket_t *, isc_socketevent_t *,
+                             struct msghdr *, struct iovec *, size_t *);
+#ifdef ISC_PLATFORM_USETHREADS
+static isc_boolean_t process_ctlfd(isc_socketmgr_t *manager);
+#endif
+
+#define SELECT_POKE_SHUTDOWN           (-1)
+#define SELECT_POKE_NOTHING            (-2)
+#define SELECT_POKE_READ               (-3)
+#define SELECT_POKE_ACCEPT             (-3) /*%< Same as _READ */
+#define SELECT_POKE_WRITE              (-4)
+#define SELECT_POKE_CONNECT            (-4) /*%< Same as _WRITE */
+#define SELECT_POKE_CLOSE              (-5)
+
+#define SOCK_DEAD(s)                   ((s)->references == 0)
+
+/*%
+ * Shortcut index arrays to get access to statistics counters.
+ */
+enum {
+       STATID_OPEN = 0,
+       STATID_OPENFAIL = 1,
+       STATID_CLOSE = 2,
+       STATID_BINDFAIL = 3,
+       STATID_CONNECTFAIL = 4,
+       STATID_CONNECT = 5,
+       STATID_ACCEPTFAIL = 6,
+       STATID_ACCEPT = 7,
+       STATID_SENDFAIL = 8,
+       STATID_RECVFAIL = 9
+};
+static const isc_statscounter_t upd4statsindex[] = {
+       isc_sockstatscounter_udp4open,
+       isc_sockstatscounter_udp4openfail,
+       isc_sockstatscounter_udp4close,
+       isc_sockstatscounter_udp4bindfail,
+       isc_sockstatscounter_udp4connectfail,
+       isc_sockstatscounter_udp4connect,
+       -1,
+       -1,
+       isc_sockstatscounter_udp4sendfail,
+       isc_sockstatscounter_udp4recvfail
+};
+static const isc_statscounter_t upd6statsindex[] = {
+       isc_sockstatscounter_udp6open,
+       isc_sockstatscounter_udp6openfail,
+       isc_sockstatscounter_udp6close,
+       isc_sockstatscounter_udp6bindfail,
+       isc_sockstatscounter_udp6connectfail,
+       isc_sockstatscounter_udp6connect,
+       -1,
+       -1,
+       isc_sockstatscounter_udp6sendfail,
+       isc_sockstatscounter_udp6recvfail
+};
+static const isc_statscounter_t tcp4statsindex[] = {
+       isc_sockstatscounter_tcp4open,
+       isc_sockstatscounter_tcp4openfail,
+       isc_sockstatscounter_tcp4close,
+       isc_sockstatscounter_tcp4bindfail,
+       isc_sockstatscounter_tcp4connectfail,
+       isc_sockstatscounter_tcp4connect,
+       isc_sockstatscounter_tcp4acceptfail,
+       isc_sockstatscounter_tcp4accept,
+       isc_sockstatscounter_tcp4sendfail,
+       isc_sockstatscounter_tcp4recvfail
+};
+static const isc_statscounter_t tcp6statsindex[] = {
+       isc_sockstatscounter_tcp6open,
+       isc_sockstatscounter_tcp6openfail,
+       isc_sockstatscounter_tcp6close,
+       isc_sockstatscounter_tcp6bindfail,
+       isc_sockstatscounter_tcp6connectfail,
+       isc_sockstatscounter_tcp6connect,
+       isc_sockstatscounter_tcp6acceptfail,
+       isc_sockstatscounter_tcp6accept,
+       isc_sockstatscounter_tcp6sendfail,
+       isc_sockstatscounter_tcp6recvfail
+};
+static const isc_statscounter_t unixstatsindex[] = {
+       isc_sockstatscounter_unixopen,
+       isc_sockstatscounter_unixopenfail,
+       isc_sockstatscounter_unixclose,
+       isc_sockstatscounter_unixbindfail,
+       isc_sockstatscounter_unixconnectfail,
+       isc_sockstatscounter_unixconnect,
+       isc_sockstatscounter_unixacceptfail,
+       isc_sockstatscounter_unixaccept,
+       isc_sockstatscounter_unixsendfail,
+       isc_sockstatscounter_unixrecvfail
+};
+static const isc_statscounter_t fdwatchstatsindex[] = {
+       -1,
+       -1,
+       isc_sockstatscounter_fdwatchclose,
+       isc_sockstatscounter_fdwatchbindfail,
+       isc_sockstatscounter_fdwatchconnectfail,
+       isc_sockstatscounter_fdwatchconnect,
+       -1,
+       -1,
+       isc_sockstatscounter_fdwatchsendfail,
+       isc_sockstatscounter_fdwatchrecvfail
+};
+
+static void
+manager_log(isc_socketmgr_t *sockmgr,
+           isc_logcategory_t *category, isc_logmodule_t *module, int level,
+           const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6);
+static void
+manager_log(isc_socketmgr_t *sockmgr,
+           isc_logcategory_t *category, isc_logmodule_t *module, int level,
+           const char *fmt, ...)
+{
+       char msgbuf[2048];
+       va_list ap;
+
+       if (! isc_log_wouldlog(isc_lctx, level))
+               return;
+
+       va_start(ap, fmt);
+       vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+       va_end(ap);
+
+       isc_log_write(isc_lctx, category, module, level,
+                     "sockmgr %p: %s", sockmgr, msgbuf);
+}
+
+static void
+socket_log(isc_socket_t *sock, isc_sockaddr_t *address,
+          isc_logcategory_t *category, isc_logmodule_t *module, int level,
+          isc_msgcat_t *msgcat, int msgset, int message,
+          const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10);
+static void
+socket_log(isc_socket_t *sock, isc_sockaddr_t *address,
+          isc_logcategory_t *category, isc_logmodule_t *module, int level,
+          isc_msgcat_t *msgcat, int msgset, int message,
+          const char *fmt, ...)
+{
+       char msgbuf[2048];
+       char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+       va_list ap;
+
+       if (! isc_log_wouldlog(isc_lctx, level))
+               return;
+
+       va_start(ap, fmt);
+       vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+       va_end(ap);
+
+       if (address == NULL) {
+               isc_log_iwrite(isc_lctx, category, module, level,
+                              msgcat, msgset, message,
+                              "socket %p: %s", sock, msgbuf);
+       } else {
+               isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
+               isc_log_iwrite(isc_lctx, category, module, level,
+                              msgcat, msgset, message,
+                              "socket %p %s: %s", sock, peerbuf, msgbuf);
+       }
+}
+
+#if defined(_AIX) && defined(ISC_NET_BSD44MSGHDR) && \
+    defined(USE_CMSG) && defined(IPV6_RECVPKTINFO)
+/*
+ * AIX has a kernel bug where IPV6_RECVPKTINFO gets cleared by
+ * setting IPV6_V6ONLY.
+ */
+static void
+FIX_IPV6_RECVPKTINFO(isc_socket_t *sock)
+{
+       char strbuf[ISC_STRERRORSIZE];
+       int on = 1;
+
+       if (sock->pf != AF_INET6 || sock->type != isc_sockettype_udp)
+               return;
+
+       if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                      (void *)&on, sizeof(on)) < 0) {
+
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "setsockopt(%d, IPV6_RECVPKTINFO) "
+                                "%s: %s", sock->fd,
+                                isc_msgcat_get(isc_msgcat,
+                                               ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED,
+                                               "failed"),
+                                strbuf);
+       }
+}
+#else
+#define FIX_IPV6_RECVPKTINFO(sock) (void)0
+#endif
+
+/*%
+ * Increment socket-related statistics counters.
+ */
+static inline void
+inc_stats(isc_stats_t *stats, isc_statscounter_t counterid) {
+       REQUIRE(counterid != -1);
+
+       if (stats != NULL)
+               isc_stats_increment(stats, counterid);
+}
+
+static inline isc_result_t
+watch_fd(isc_socketmgr_t *manager, int fd, int msg) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+#ifdef USE_KQUEUE
+       struct kevent evchange;
+
+       memset(&evchange, 0, sizeof(evchange));
+       if (msg == SELECT_POKE_READ)
+               evchange.filter = EVFILT_READ;
+       else
+               evchange.filter = EVFILT_WRITE;
+       evchange.flags = EV_ADD;
+       evchange.ident = fd;
+       if (kevent(manager->kqueue_fd, &evchange, 1, NULL, 0, NULL) != 0)
+               result = isc__errno2result(errno);
+
+       return (result);
+#elif defined(USE_EPOLL)
+       struct epoll_event event;
+
+       if (msg == SELECT_POKE_READ)
+               event.events = EPOLLIN;
+       else
+               event.events = EPOLLOUT;
+       event.data.fd = fd;
+       if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1 &&
+           errno != EEXIST) {
+               result = isc__errno2result(errno);
+       }
+
+       return (result);
+#elif defined(USE_DEVPOLL)
+       struct pollfd pfd;
+       int lockid = FDLOCK_ID(fd);
+
+       memset(&pfd, 0, sizeof(pfd));
+       if (msg == SELECT_POKE_READ)
+               pfd.events = POLLIN;
+       else
+               pfd.events = POLLOUT;
+       pfd.fd = fd;
+       pfd.revents = 0;
+       LOCK(&manager->fdlock[lockid]);
+       if (write(manager->devpoll_fd, &pfd, sizeof(pfd)) == -1)
+               result = isc__errno2result(errno);
+       else {
+               if (msg == SELECT_POKE_READ)
+                       manager->fdpollinfo[fd].want_read = 1;
+               else
+                       manager->fdpollinfo[fd].want_write = 1;
+       }
+       UNLOCK(&manager->fdlock[lockid]);
+
+       return (result);
+#elif defined(USE_SELECT)
+       LOCK(&manager->lock);
+       if (msg == SELECT_POKE_READ)
+               FD_SET(fd, manager->read_fds);
+       if (msg == SELECT_POKE_WRITE)
+               FD_SET(fd, manager->write_fds);
+       UNLOCK(&manager->lock);
+
+       return (result);
+#endif
+}
+
+static inline isc_result_t
+unwatch_fd(isc_socketmgr_t *manager, int fd, int msg) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+#ifdef USE_KQUEUE
+       struct kevent evchange;
+
+       memset(&evchange, 0, sizeof(evchange));
+       if (msg == SELECT_POKE_READ)
+               evchange.filter = EVFILT_READ;
+       else
+               evchange.filter = EVFILT_WRITE;
+       evchange.flags = EV_DELETE;
+       evchange.ident = fd;
+       if (kevent(manager->kqueue_fd, &evchange, 1, NULL, 0, NULL) != 0)
+               result = isc__errno2result(errno);
+
+       return (result);
+#elif defined(USE_EPOLL)
+       struct epoll_event event;
+
+       if (msg == SELECT_POKE_READ)
+               event.events = EPOLLIN;
+       else
+               event.events = EPOLLOUT;
+       event.data.fd = fd;
+       if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_DEL, fd, &event) == -1 &&
+           errno != ENOENT) {
+               char strbuf[ISC_STRERRORSIZE];
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "epoll_ctl(DEL), %d: %s", fd, strbuf);
+               result = ISC_R_UNEXPECTED;
+       }
+       return (result);
+#elif defined(USE_DEVPOLL)
+       struct pollfd pfds[2];
+       size_t writelen = sizeof(pfds[0]);
+       int lockid = FDLOCK_ID(fd);
+
+       memset(pfds, 0, sizeof(pfds));
+       pfds[0].events = POLLREMOVE;
+       pfds[0].fd = fd;
+
+       /*
+        * Canceling read or write polling via /dev/poll is tricky.  Since it
+        * only provides a way of canceling per FD, we may need to re-poll the
+        * socket for the other operation.
+        */
+       LOCK(&manager->fdlock[lockid]);
+       if (msg == SELECT_POKE_READ &&
+           manager->fdpollinfo[fd].want_write == 1) {
+               pfds[1].events = POLLOUT;
+               pfds[1].fd = fd;
+               writelen += sizeof(pfds[1]);
+       }
+       if (msg == SELECT_POKE_WRITE &&
+           manager->fdpollinfo[fd].want_read == 1) {
+               pfds[1].events = POLLIN;
+               pfds[1].fd = fd;
+               writelen += sizeof(pfds[1]);
+       }
+
+       if (write(manager->devpoll_fd, pfds, writelen) == -1)
+               result = isc__errno2result(errno);
+       else {
+               if (msg == SELECT_POKE_READ)
+                       manager->fdpollinfo[fd].want_read = 0;
+               else
+                       manager->fdpollinfo[fd].want_write = 0;
+       }
+       UNLOCK(&manager->fdlock[lockid]);
+
+       return (result);
+#elif defined(USE_SELECT)
+       LOCK(&manager->lock);
+       if (msg == SELECT_POKE_READ)
+               FD_CLR(fd, manager->read_fds);
+       else if (msg == SELECT_POKE_WRITE)
+               FD_CLR(fd, manager->write_fds);
+       UNLOCK(&manager->lock);
+
+       return (result);
+#endif
+}
+
+static void
+wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) {
+       isc_result_t result;
+       int lockid = FDLOCK_ID(fd);
+
+       /*
+        * This is a wakeup on a socket.  If the socket is not in the
+        * process of being closed, start watching it for either reads
+        * or writes.
+        */
+
+       INSIST(fd >= 0 && fd < (int)manager->maxsocks);
+
+       if (msg == SELECT_POKE_CLOSE) {
+               /* No one should be updating fdstate, so no need to lock it */
+               INSIST(manager->fdstate[fd] == CLOSE_PENDING);
+               manager->fdstate[fd] = CLOSED;
+               (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+               (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+               (void)close(fd);
+               return;
+       }
+
+       LOCK(&manager->fdlock[lockid]);
+       if (manager->fdstate[fd] == CLOSE_PENDING) {
+               UNLOCK(&manager->fdlock[lockid]);
+
+               /*
+                * We accept (and ignore) any error from unwatch_fd() as we are
+                * closing the socket, hoping it doesn't leave dangling state in
+                * the kernel.
+                * Note that unwatch_fd() must be called after releasing the
+                * fdlock; otherwise it could cause deadlock due to a lock order
+                * reversal.
+                */
+               (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+               (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+               return;
+       }
+       if (manager->fdstate[fd] != MANAGED) {
+               UNLOCK(&manager->fdlock[lockid]);
+               return;
+       }
+       UNLOCK(&manager->fdlock[lockid]);
+
+       /*
+        * Set requested bit.
+        */
+       result = watch_fd(manager, fd, msg);
+       if (result != ISC_R_SUCCESS) {
+               /*
+                * XXXJT: what should we do?  Ignoring the failure of watching
+                * a socket will make the application dysfunctional, but there
+                * seems to be no reasonable recovery process.
+                */
+               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                             ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                             "failed to start watching FD (%d): %s",
+                             fd, isc_result_totext(result));
+       }
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+/*
+ * Poke the select loop when there is something for us to do.
+ * The write is required (by POSIX) to complete.  That is, we
+ * will not get partial writes.
+ */
+static void
+select_poke(isc_socketmgr_t *mgr, int fd, int msg) {
+       int cc;
+       int buf[2];
+       char strbuf[ISC_STRERRORSIZE];
+
+       buf[0] = fd;
+       buf[1] = msg;
+
+       do {
+               cc = write(mgr->pipe_fds[1], buf, sizeof(buf));
+#ifdef ENOSR
+               /*
+                * Treat ENOSR as EAGAIN but loop slowly as it is
+                * unlikely to clear fast.
+                */
+               if (cc < 0 && errno == ENOSR) {
+                       sleep(1);
+                       errno = EAGAIN;
+               }
+#endif
+       } while (cc < 0 && SOFT_ERROR(errno));
+
+       if (cc < 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               FATAL_ERROR(__FILE__, __LINE__,
+                           isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                                          ISC_MSG_WRITEFAILED,
+                                          "write() failed "
+                                          "during watcher poke: %s"),
+                           strbuf);
+       }
+
+       INSIST(cc == sizeof(buf));
+}
+
+/*
+ * Read a message on the internal fd.
+ */
+static void
+select_readmsg(isc_socketmgr_t *mgr, int *fd, int *msg) {
+       int buf[2];
+       int cc;
+       char strbuf[ISC_STRERRORSIZE];
+
+       cc = read(mgr->pipe_fds[0], buf, sizeof(buf));
+       if (cc < 0) {
+               *msg = SELECT_POKE_NOTHING;
+               *fd = -1;       /* Silence compiler. */
+               if (SOFT_ERROR(errno))
+                       return;
+
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               FATAL_ERROR(__FILE__, __LINE__,
+                           isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                                          ISC_MSG_READFAILED,
+                                          "read() failed "
+                                          "during watcher poke: %s"),
+                           strbuf);
+
+               return;
+       }
+       INSIST(cc == sizeof(buf));
+
+       *fd = buf[0];
+       *msg = buf[1];
+}
+#else /* ISC_PLATFORM_USETHREADS */
+/*
+ * Update the state of the socketmgr when something changes.
+ */
+static void
+select_poke(isc_socketmgr_t *manager, int fd, int msg) {
+       if (msg == SELECT_POKE_SHUTDOWN)
+               return;
+       else if (fd >= 0)
+               wakeup_socket(manager, fd, msg);
+       return;
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/*
+ * Make a fd non-blocking.
+ */
+static isc_result_t
+make_nonblock(int fd) {
+       int ret;
+       int flags;
+       char strbuf[ISC_STRERRORSIZE];
+#ifdef USE_FIONBIO_IOCTL
+       int on = 1;
+
+       ret = ioctl(fd, FIONBIO, (char *)&on);
+#else
+       flags = fcntl(fd, F_GETFL, 0);
+       flags |= PORT_NONBLOCK;
+       ret = fcntl(fd, F_SETFL, flags);
+#endif
+
+       if (ret == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+#ifdef USE_FIONBIO_IOCTL
+                                "ioctl(%d, FIONBIO, &on): %s", fd,
+#else
+                                "fcntl(%d, F_SETFL, %d): %s", fd, flags,
+#endif
+                                strbuf);
+
+               return (ISC_R_UNEXPECTED);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+#ifdef USE_CMSG
+/*
+ * Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
+ * In order to ensure as much portability as possible, we provide wrapper
+ * functions of these macros.
+ * Note that cmsg_space() could run slow on OSes that do not have
+ * CMSG_SPACE.
+ */
+static inline ISC_SOCKADDR_LEN_T
+cmsg_len(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_LEN
+       return (CMSG_LEN(len));
+#else
+       ISC_SOCKADDR_LEN_T hdrlen;
+
+       /*
+        * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
+        * is correct.
+        */
+       hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL));
+       return (hdrlen + len);
+#endif
+}
+
+static inline ISC_SOCKADDR_LEN_T
+cmsg_space(ISC_SOCKADDR_LEN_T len) {
+#ifdef CMSG_SPACE
+       return (CMSG_SPACE(len));
+#else
+       struct msghdr msg;
+       struct cmsghdr *cmsgp;
+       /*
+        * XXX: The buffer length is an ad-hoc value, but should be enough
+        * in a practical sense.
+        */
+       char dummybuf[sizeof(struct cmsghdr) + 1024];
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_control = dummybuf;
+       msg.msg_controllen = sizeof(dummybuf);
+
+       cmsgp = (struct cmsghdr *)dummybuf;
+       cmsgp->cmsg_len = cmsg_len(len);
+
+       cmsgp = CMSG_NXTHDR(&msg, cmsgp);
+       if (cmsgp != NULL)
+               return ((char *)cmsgp - (char *)msg.msg_control);
+       else
+               return (0);
+#endif
+}
+#endif /* USE_CMSG */
+
+/*
+ * Process control messages received on a socket.
+ */
+static void
+process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) {
+#ifdef USE_CMSG
+       struct cmsghdr *cmsgp;
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+       struct in6_pktinfo *pktinfop;
+#endif
+#ifdef SO_TIMESTAMP
+       struct timeval *timevalp;
+#endif
+#endif
+
+       /*
+        * sock is used only when ISC_NET_BSD44MSGHDR and USE_CMSG are defined.
+        * msg and dev are used only when ISC_NET_BSD44MSGHDR is defined.
+        * They are all here, outside of the CPP tests, because it is
+        * more consistent with the usual ISC coding style.
+        */
+       UNUSED(sock);
+       UNUSED(msg);
+       UNUSED(dev);
+
+#ifdef ISC_NET_BSD44MSGHDR
+
+#ifdef MSG_TRUNC
+       if ((msg->msg_flags & MSG_TRUNC) == MSG_TRUNC)
+               dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
+#endif
+
+#ifdef MSG_CTRUNC
+       if ((msg->msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
+               dev->attributes |= ISC_SOCKEVENTATTR_CTRUNC;
+#endif
+
+#ifndef USE_CMSG
+       return;
+#else
+       if (msg->msg_controllen == 0U || msg->msg_control == NULL)
+               return;
+
+#ifdef SO_TIMESTAMP
+       timevalp = NULL;
+#endif
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+       pktinfop = NULL;
+#endif
+
+       cmsgp = CMSG_FIRSTHDR(msg);
+       while (cmsgp != NULL) {
+               socket_log(sock, NULL, TRACE,
+                          isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PROCESSCMSG,
+                          "processing cmsg %p", cmsgp);
+
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+               if (cmsgp->cmsg_level == IPPROTO_IPV6
+                   && cmsgp->cmsg_type == IPV6_PKTINFO) {
+
+                       pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
+                       memcpy(&dev->pktinfo, pktinfop,
+                              sizeof(struct in6_pktinfo));
+                       dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
+                       socket_log(sock, NULL, TRACE,
+                                  isc_msgcat, ISC_MSGSET_SOCKET,
+                                  ISC_MSG_IFRECEIVED,
+                                  "interface received on ifindex %u",
+                                  dev->pktinfo.ipi6_ifindex);
+                       if (IN6_IS_ADDR_MULTICAST(&pktinfop->ipi6_addr))
+                               dev->attributes |= ISC_SOCKEVENTATTR_MULTICAST;
+                       goto next;
+               }
+#endif
+
+#ifdef SO_TIMESTAMP
+               if (cmsgp->cmsg_level == SOL_SOCKET
+                   && cmsgp->cmsg_type == SCM_TIMESTAMP) {
+                       timevalp = (struct timeval *)CMSG_DATA(cmsgp);
+                       dev->timestamp.seconds = timevalp->tv_sec;
+                       dev->timestamp.nanoseconds = timevalp->tv_usec * 1000;
+                       dev->attributes |= ISC_SOCKEVENTATTR_TIMESTAMP;
+                       goto next;
+               }
+#endif
+
+       next:
+               cmsgp = CMSG_NXTHDR(msg, cmsgp);
+       }
+#endif /* USE_CMSG */
+
+#endif /* ISC_NET_BSD44MSGHDR */
+}
+
+/*
+ * Construct an iov array and attach it to the msghdr passed in.  This is
+ * the SEND constructor, which will use the used region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
+ *
+ * Nothing can be NULL, and the done event must list at least one buffer
+ * on the buffer linked list for this function to be meaningful.
+ *
+ * If write_countp != NULL, *write_countp will hold the number of bytes
+ * this transaction can send.
+ */
+static void
+build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
+                 struct msghdr *msg, struct iovec *iov, size_t *write_countp)
+{
+       unsigned int iovcount;
+       isc_buffer_t *buffer;
+       isc_region_t used;
+       size_t write_count;
+       size_t skip_count;
+
+       memset(msg, 0, sizeof(*msg));
+
+       if (!sock->connected) {
+               msg->msg_name = (void *)&dev->address.type.sa;
+               msg->msg_namelen = dev->address.length;
+       } else {
+               msg->msg_name = NULL;
+               msg->msg_namelen = 0;
+       }
+
+       buffer = ISC_LIST_HEAD(dev->bufferlist);
+       write_count = 0;
+       iovcount = 0;
+
+       /*
+        * Single buffer I/O?  Skip what we've done so far in this region.
+        */
+       if (buffer == NULL) {
+               write_count = dev->region.length - dev->n;
+               iov[0].iov_base = (void *)(dev->region.base + dev->n);
+               iov[0].iov_len = write_count;
+               iovcount = 1;
+
+               goto config;
+       }
+
+       /*
+        * Multibuffer I/O.
+        * Skip the data in the buffer list that we have already written.
+        */
+       skip_count = dev->n;
+       while (buffer != NULL) {
+               REQUIRE(ISC_BUFFER_VALID(buffer));
+               if (skip_count < isc_buffer_usedlength(buffer))
+                       break;
+               skip_count -= isc_buffer_usedlength(buffer);
+               buffer = ISC_LIST_NEXT(buffer, link);
+       }
+
+       while (buffer != NULL) {
+               INSIST(iovcount < MAXSCATTERGATHER_SEND);
+
+               isc_buffer_usedregion(buffer, &used);
+
+               if (used.length > 0) {
+                       iov[iovcount].iov_base = (void *)(used.base
+                                                         + skip_count);
+                       iov[iovcount].iov_len = used.length - skip_count;
+                       write_count += (used.length - skip_count);
+                       skip_count = 0;
+                       iovcount++;
+               }
+               buffer = ISC_LIST_NEXT(buffer, link);
+       }
+
+       INSIST(skip_count == 0U);
+
+ config:
+       msg->msg_iov = iov;
+       msg->msg_iovlen = iovcount;
+
+#ifdef ISC_NET_BSD44MSGHDR
+       msg->msg_control = NULL;
+       msg->msg_controllen = 0;
+       msg->msg_flags = 0;
+#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+       if ((sock->type == isc_sockettype_udp)
+           && ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0)) {
+               struct cmsghdr *cmsgp;
+               struct in6_pktinfo *pktinfop;
+
+               socket_log(sock, NULL, TRACE,
+                          isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_SENDTODATA,
+                          "sendto pktinfo data, ifindex %u",
+                          dev->pktinfo.ipi6_ifindex);
+
+               msg->msg_controllen = cmsg_space(sizeof(struct in6_pktinfo));
+               INSIST(msg->msg_controllen <= sock->sendcmsgbuflen);
+               msg->msg_control = (void *)sock->sendcmsgbuf;
+
+               cmsgp = (struct cmsghdr *)sock->sendcmsgbuf;
+               cmsgp->cmsg_level = IPPROTO_IPV6;
+               cmsgp->cmsg_type = IPV6_PKTINFO;
+               cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo));
+               pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
+               memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo));
+       }
+#endif /* USE_CMSG && ISC_PLATFORM_HAVEIPV6 */
+#else /* ISC_NET_BSD44MSGHDR */
+       msg->msg_accrights = NULL;
+       msg->msg_accrightslen = 0;
+#endif /* ISC_NET_BSD44MSGHDR */
+
+       if (write_countp != NULL)
+               *write_countp = write_count;
+}
+
+/*
+ * Construct an iov array and attach it to the msghdr passed in.  This is
+ * the RECV constructor, which will use the available region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
+ *
+ * Nothing can be NULL, and the done event must list at least one buffer
+ * on the buffer linked list for this function to be meaningful.
+ *
+ * If read_countp != NULL, *read_countp will hold the number of bytes
+ * this transaction can receive.
+ */
+static void
+build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
+                 struct msghdr *msg, struct iovec *iov, size_t *read_countp)
+{
+       unsigned int iovcount;
+       isc_buffer_t *buffer;
+       isc_region_t available;
+       size_t read_count;
+
+       memset(msg, 0, sizeof(struct msghdr));
+
+       if (sock->type == isc_sockettype_udp) {
+               memset(&dev->address, 0, sizeof(dev->address));
+#ifdef BROKEN_RECVMSG
+               if (sock->pf == AF_INET) {
+                       msg->msg_name = (void *)&dev->address.type.sin;
+                       msg->msg_namelen = sizeof(dev->address.type.sin6);
+               } else if (sock->pf == AF_INET6) {
+                       msg->msg_name = (void *)&dev->address.type.sin6;
+                       msg->msg_namelen = sizeof(dev->address.type.sin6);
+#ifdef ISC_PLATFORM_HAVESYSUNH
+               } else if (sock->pf == AF_UNIX) {
+                       msg->msg_name = (void *)&dev->address.type.sunix;
+                       msg->msg_namelen = sizeof(dev->address.type.sunix);
+#endif
+               } else {
+                       msg->msg_name = (void *)&dev->address.type.sa;
+                       msg->msg_namelen = sizeof(dev->address.type);
+               }
+#else
+               msg->msg_name = (void *)&dev->address.type.sa;
+               msg->msg_namelen = sizeof(dev->address.type);
+#endif
+#ifdef ISC_NET_RECVOVERFLOW
+               /* If needed, steal one iovec for overflow detection. */
+               maxiov--;
+#endif
+       } else { /* TCP */
+               msg->msg_name = NULL;
+               msg->msg_namelen = 0;
+               dev->address = sock->peer_address;
+       }
+
+       buffer = ISC_LIST_HEAD(dev->bufferlist);
+       read_count = 0;
+
+       /*
+        * Single buffer I/O?  Skip what we've done so far in this region.
+        */
+       if (buffer == NULL) {
+               read_count = dev->region.length - dev->n;
+               iov[0].iov_base = (void *)(dev->region.base + dev->n);
+               iov[0].iov_len = read_count;
+               iovcount = 1;
+
+               goto config;
+       }
+
+       /*
+        * Multibuffer I/O.
+        * Skip empty buffers.
+        */
+       while (buffer != NULL) {
+               REQUIRE(ISC_BUFFER_VALID(buffer));
+               if (isc_buffer_availablelength(buffer) != 0)
+                       break;
+               buffer = ISC_LIST_NEXT(buffer, link);
+       }
+
+       iovcount = 0;
+       while (buffer != NULL) {
+               INSIST(iovcount < MAXSCATTERGATHER_RECV);
+
+               isc_buffer_availableregion(buffer, &available);
+
+               if (available.length > 0) {
+                       iov[iovcount].iov_base = (void *)(available.base);
+                       iov[iovcount].iov_len = available.length;
+                       read_count += available.length;
+                       iovcount++;
+               }
+               buffer = ISC_LIST_NEXT(buffer, link);
+       }
+
+ config:
+
+       /*
+        * If needed, set up to receive that one extra byte.  Note that
+        * we know there is at least one iov left, since we stole it
+        * at the top of this function.
+        */
+#ifdef ISC_NET_RECVOVERFLOW
+       if (sock->type == isc_sockettype_udp) {
+               iov[iovcount].iov_base = (void *)(&sock->overflow);
+               iov[iovcount].iov_len = 1;
+               iovcount++;
+       }
+#endif
+
+       msg->msg_iov = iov;
+       msg->msg_iovlen = iovcount;
+
+#ifdef ISC_NET_BSD44MSGHDR
+       msg->msg_control = NULL;
+       msg->msg_controllen = 0;
+       msg->msg_flags = 0;
+#if defined(USE_CMSG)
+       if (sock->type == isc_sockettype_udp) {
+               msg->msg_control = sock->recvcmsgbuf;
+               msg->msg_controllen = sock->recvcmsgbuflen;
+       }
+#endif /* USE_CMSG */
+#else /* ISC_NET_BSD44MSGHDR */
+       msg->msg_accrights = NULL;
+       msg->msg_accrightslen = 0;
+#endif /* ISC_NET_BSD44MSGHDR */
+
+       if (read_countp != NULL)
+               *read_countp = read_count;
+}
+
+static void
+set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
+               isc_socketevent_t *dev)
+{
+       if (sock->type == isc_sockettype_udp) {
+               if (address != NULL)
+                       dev->address = *address;
+               else
+                       dev->address = sock->peer_address;
+       } else if (sock->type == isc_sockettype_tcp) {
+               INSIST(address == NULL);
+               dev->address = sock->peer_address;
+       }
+}
+
+static void
+destroy_socketevent(isc_event_t *event) {
+       isc_socketevent_t *ev = (isc_socketevent_t *)event;
+
+       INSIST(ISC_LIST_EMPTY(ev->bufferlist));
+
+       (ev->destroy)(event);
+}
+
+static isc_socketevent_t *
+allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype,
+                    isc_taskaction_t action, const void *arg)
+{
+       isc_socketevent_t *ev;
+
+       ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx,
+                                                    sock, eventtype,
+                                                    action, arg,
+                                                    sizeof(*ev));
+
+       if (ev == NULL)
+               return (NULL);
+
+       ev->result = ISC_R_UNEXPECTED;
+       ISC_LINK_INIT(ev, ev_link);
+       ISC_LIST_INIT(ev->bufferlist);
+       ev->region.base = NULL;
+       ev->n = 0;
+       ev->offset = 0;
+       ev->attributes = 0;
+       ev->destroy = ev->ev_destroy;
+       ev->ev_destroy = destroy_socketevent;
+
+       return (ev);
+}
+
+#if defined(ISC_SOCKET_DEBUG)
+static void
+dump_msg(struct msghdr *msg) {
+       unsigned int i;
+
+       printf("MSGHDR %p\n", msg);
+       printf("\tname %p, namelen %ld\n", msg->msg_name,
+              (long) msg->msg_namelen);
+       printf("\tiov %p, iovlen %ld\n", msg->msg_iov,
+              (long) msg->msg_iovlen);
+       for (i = 0; i < (unsigned int)msg->msg_iovlen; i++)
+               printf("\t\t%d\tbase %p, len %ld\n", i,
+                      msg->msg_iov[i].iov_base,
+                      (long) msg->msg_iov[i].iov_len);
+#ifdef ISC_NET_BSD44MSGHDR
+       printf("\tcontrol %p, controllen %ld\n", msg->msg_control,
+              (long) msg->msg_controllen);
+#endif
+}
+#endif
+
+#define DOIO_SUCCESS           0       /* i/o ok, event sent */
+#define DOIO_SOFT              1       /* i/o ok, soft error, no event sent */
+#define DOIO_HARD              2       /* i/o error, event sent */
+#define DOIO_EOF               3       /* EOF, no event sent */
+
+static int
+doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
+       int cc;
+       struct iovec iov[MAXSCATTERGATHER_RECV];
+       size_t read_count;
+       size_t actual_count;
+       struct msghdr msghdr;
+       isc_buffer_t *buffer;
+       int recv_errno;
+       char strbuf[ISC_STRERRORSIZE];
+
+       build_msghdr_recv(sock, dev, &msghdr, iov, &read_count);
+
+#if defined(ISC_SOCKET_DEBUG)
+       dump_msg(&msghdr);
+#endif
+
+       cc = recvmsg(sock->fd, &msghdr, 0);
+       recv_errno = errno;
+
+#if defined(ISC_SOCKET_DEBUG)
+       dump_msg(&msghdr);
+#endif
+
+       if (cc < 0) {
+               if (SOFT_ERROR(recv_errno))
+                       return (DOIO_SOFT);
+
+               if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+                       isc__strerror(recv_errno, strbuf, sizeof(strbuf));
+                       socket_log(sock, NULL, IOEVENT,
+                                  isc_msgcat, ISC_MSGSET_SOCKET,
+                                  ISC_MSG_DOIORECV,
+                                 "doio_recv: recvmsg(%d) %d bytes, err %d/%s",
+                                  sock->fd, cc, recv_errno, strbuf);
+               }
+
+#define SOFT_OR_HARD(_system, _isc) \
+       if (recv_errno == _system) { \
+               if (sock->connected) { \
+                       dev->result = _isc; \
+                       inc_stats(sock->manager->stats, \
+                                 sock->statsindex[STATID_RECVFAIL]); \
+                       return (DOIO_HARD); \
+               } \
+               return (DOIO_SOFT); \
+       }
+#define ALWAYS_HARD(_system, _isc) \
+       if (recv_errno == _system) { \
+               dev->result = _isc; \
+               inc_stats(sock->manager->stats, \
+                         sock->statsindex[STATID_RECVFAIL]); \
+               return (DOIO_HARD); \
+       }
+
+               SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
+               SOFT_OR_HARD(ENETUNREACH, ISC_R_NETUNREACH);
+               SOFT_OR_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+               SOFT_OR_HARD(EHOSTDOWN, ISC_R_HOSTDOWN);
+               /* HPUX 11.11 can return EADDRNOTAVAIL. */
+               SOFT_OR_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+               ALWAYS_HARD(ENOBUFS, ISC_R_NORESOURCES);
+               /*
+                * HPUX returns EPROTO and EINVAL on receiving some ICMP/ICMPv6
+                * errors.
+                */
+#ifdef EPROTO
+               SOFT_OR_HARD(EPROTO, ISC_R_HOSTUNREACH);
+#endif
+               SOFT_OR_HARD(EINVAL, ISC_R_HOSTUNREACH);
+
+#undef SOFT_OR_HARD
+#undef ALWAYS_HARD
+
+               dev->result = isc__errno2result(recv_errno);
+               inc_stats(sock->manager->stats,
+                         sock->statsindex[STATID_RECVFAIL]);
+               return (DOIO_HARD);
+       }
+
+       /*
+        * On TCP, zero length reads indicate EOF, while on
+        * UDP, zero length reads are perfectly valid, although
+        * strange.
+        */
+       if ((sock->type == isc_sockettype_tcp) && (cc == 0))
+               return (DOIO_EOF);
+
+       if (sock->type == isc_sockettype_udp) {
+               dev->address.length = msghdr.msg_namelen;
+               if (isc_sockaddr_getport(&dev->address) == 0) {
+                       if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+                               socket_log(sock, &dev->address, IOEVENT,
+                                          isc_msgcat, ISC_MSGSET_SOCKET,
+                                          ISC_MSG_ZEROPORT,
+                                          "dropping source port zero packet");
+                       }
+                       return (DOIO_SOFT);
+               }
+       }
+
+       socket_log(sock, &dev->address, IOEVENT,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PKTRECV,
+                  "packet received correctly");
+
+       /*
+        * Overflow bit detection.  If we received MORE bytes than we should,
+        * this indicates an overflow situation.  Set the flag in the
+        * dev entry and adjust how much we read by one.
+        */
+#ifdef ISC_NET_RECVOVERFLOW
+       if ((sock->type == isc_sockettype_udp) && ((size_t)cc > read_count)) {
+               dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
+               cc--;
+       }
+#endif
+
+       /*
+        * If there are control messages attached, run through them and pull
+        * out the interesting bits.
+        */
+       if (sock->type == isc_sockettype_udp)
+               process_cmsg(sock, &msghdr, dev);
+
+       /*
+        * update the buffers (if any) and the i/o count
+        */
+       dev->n += cc;
+       actual_count = cc;
+       buffer = ISC_LIST_HEAD(dev->bufferlist);
+       while (buffer != NULL && actual_count > 0U) {
+               REQUIRE(ISC_BUFFER_VALID(buffer));
+               if (isc_buffer_availablelength(buffer) <= actual_count) {
+                       actual_count -= isc_buffer_availablelength(buffer);
+                       isc_buffer_add(buffer,
+                                      isc_buffer_availablelength(buffer));
+               } else {
+                       isc_buffer_add(buffer, actual_count);
+                       actual_count = 0;
+                       break;
+               }
+               buffer = ISC_LIST_NEXT(buffer, link);
+               if (buffer == NULL) {
+                       INSIST(actual_count == 0U);
+               }
+       }
+
+       /*
+        * If we read less than we expected, update counters,
+        * and let the upper layer poke the descriptor.
+        */
+       if (((size_t)cc != read_count) && (dev->n < dev->minimum))
+               return (DOIO_SOFT);
+
+       /*
+        * Full reads are posted, or partials if partials are ok.
+        */
+       dev->result = ISC_R_SUCCESS;
+       return (DOIO_SUCCESS);
+}
+
+/*
+ * Returns:
+ *     DOIO_SUCCESS    The operation succeeded.  dev->result contains
+ *                     ISC_R_SUCCESS.
+ *
+ *     DOIO_HARD       A hard or unexpected I/O error was encountered.
+ *                     dev->result contains the appropriate error.
+ *
+ *     DOIO_SOFT       A soft I/O error was encountered.  No senddone
+ *                     event was sent.  The operation should be retried.
+ *
+ *     No other return values are possible.
+ */
+static int
+doio_send(isc_socket_t *sock, isc_socketevent_t *dev) {
+       int cc;
+       struct iovec iov[MAXSCATTERGATHER_SEND];
+       size_t write_count;
+       struct msghdr msghdr;
+       char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+       int attempts = 0;
+       int send_errno;
+       char strbuf[ISC_STRERRORSIZE];
+
+       build_msghdr_send(sock, dev, &msghdr, iov, &write_count);
+
+ resend:
+       cc = sendmsg(sock->fd, &msghdr, 0);
+       send_errno = errno;
+
+       /*
+        * Check for error or block condition.
+        */
+       if (cc < 0) {
+               if (send_errno == EINTR && ++attempts < NRETRIES)
+                       goto resend;
+
+               if (SOFT_ERROR(send_errno))
+                       return (DOIO_SOFT);
+
+#define SOFT_OR_HARD(_system, _isc) \
+       if (send_errno == _system) { \
+               if (sock->connected) { \
+                       dev->result = _isc; \
+                       inc_stats(sock->manager->stats, \
+                                 sock->statsindex[STATID_SENDFAIL]); \
+                       return (DOIO_HARD); \
+               } \
+               return (DOIO_SOFT); \
+       }
+#define ALWAYS_HARD(_system, _isc) \
+       if (send_errno == _system) { \
+               dev->result = _isc; \
+               inc_stats(sock->manager->stats, \
+                         sock->statsindex[STATID_SENDFAIL]); \
+               return (DOIO_HARD); \
+       }
+
+               SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
+               ALWAYS_HARD(EACCES, ISC_R_NOPERM);
+               ALWAYS_HARD(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+               ALWAYS_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+               ALWAYS_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+#ifdef EHOSTDOWN
+               ALWAYS_HARD(EHOSTDOWN, ISC_R_HOSTUNREACH);
+#endif
+               ALWAYS_HARD(ENETUNREACH, ISC_R_NETUNREACH);
+               ALWAYS_HARD(ENOBUFS, ISC_R_NORESOURCES);
+               ALWAYS_HARD(EPERM, ISC_R_HOSTUNREACH);
+               ALWAYS_HARD(EPIPE, ISC_R_NOTCONNECTED);
+               ALWAYS_HARD(ECONNRESET, ISC_R_CONNECTIONRESET);
+
+#undef SOFT_OR_HARD
+#undef ALWAYS_HARD
+
+               /*
+                * The other error types depend on whether or not the
+                * socket is UDP or TCP.  If it is UDP, some errors
+                * that we expect to be fatal under TCP are merely
+                * annoying, and are really soft errors.
+                *
+                * However, these soft errors are still returned as
+                * a status.
+                */
+               isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf));
+               isc__strerror(send_errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__, "internal_send: %s: %s",
+                                addrbuf, strbuf);
+               dev->result = isc__errno2result(send_errno);
+               inc_stats(sock->manager->stats,
+                         sock->statsindex[STATID_SENDFAIL]);
+               return (DOIO_HARD);
+       }
+
+       if (cc == 0) {
+               inc_stats(sock->manager->stats,
+                         sock->statsindex[STATID_SENDFAIL]);
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "doio_send: send() %s 0",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_RETURNED, "returned"));
+       }
+
+       /*
+        * If we write less than we expected, update counters, poke.
+        */
+       dev->n += cc;
+       if ((size_t)cc != write_count)
+               return (DOIO_SOFT);
+
+       /*
+        * Exactly what we wanted to write.  We're done with this
+        * entry.  Post its completion event.
+        */
+       dev->result = ISC_R_SUCCESS;
+       return (DOIO_SUCCESS);
+}
+
+/*
+ * Kill.
+ *
+ * Caller must ensure that the socket is not locked and no external
+ * references exist.
+ */
+static void
+closesocket(isc_socketmgr_t *manager, isc_socket_t *sock, int fd) {
+       isc_sockettype_t type = sock->type;
+       int lockid = FDLOCK_ID(fd);
+
+       /*
+        * No one has this socket open, so the watcher doesn't have to be
+        * poked, and the socket doesn't have to be locked.
+        */
+       LOCK(&manager->fdlock[lockid]);
+       manager->fds[fd] = NULL;
+       if (type == isc_sockettype_fdwatch)
+               manager->fdstate[fd] = CLOSED;
+       else
+               manager->fdstate[fd] = CLOSE_PENDING;
+       UNLOCK(&manager->fdlock[lockid]);
+       if (type == isc_sockettype_fdwatch) {
+               /*
+                * The caller may close the socket once this function returns,
+                * and `fd' may be reassigned for a new socket.  So we do
+                * unwatch_fd() here, rather than defer it via select_poke().
+                * Note: this may complicate data protection among threads and
+                * may reduce performance due to additional locks.  One way to
+                * solve this would be to dup() the watched descriptor, but we
+                * take a simpler approach at this moment.
+                */
+               (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+               (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+       } else
+               select_poke(manager, fd, SELECT_POKE_CLOSE);
+
+       inc_stats(manager->stats, sock->statsindex[STATID_CLOSE]);
+
+       /*
+        * update manager->maxfd here (XXX: this should be implemented more
+        * efficiently)
+        */
+#ifdef USE_SELECT
+       LOCK(&manager->lock);
+       if (manager->maxfd == fd) {
+               int i;
+
+               manager->maxfd = 0;
+               for (i = fd - 1; i >= 0; i--) {
+                       lockid = FDLOCK_ID(i);
+
+                       LOCK(&manager->fdlock[lockid]);
+                       if (manager->fdstate[i] == MANAGED) {
+                               manager->maxfd = i;
+                               UNLOCK(&manager->fdlock[lockid]);
+                               break;
+                       }
+                       UNLOCK(&manager->fdlock[lockid]);
+               }
+#ifdef ISC_PLATFORM_USETHREADS
+               if (manager->maxfd < manager->pipe_fds[0])
+                       manager->maxfd = manager->pipe_fds[0];
+#endif
+       }
+       UNLOCK(&manager->lock);
+#endif /* USE_SELECT */
+}
+
+static void
+destroy(isc_socket_t **sockp) {
+       int fd;
+       isc_socket_t *sock = *sockp;
+       isc_socketmgr_t *manager = sock->manager;
+
+       socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+                  ISC_MSG_DESTROYING, "destroying");
+
+       INSIST(ISC_LIST_EMPTY(sock->accept_list));
+       INSIST(ISC_LIST_EMPTY(sock->recv_list));
+       INSIST(ISC_LIST_EMPTY(sock->send_list));
+       INSIST(sock->connect_ev == NULL);
+       REQUIRE(sock->fd == -1 || sock->fd < (int)manager->maxsocks);
+
+       if (sock->fd >= 0) {
+               fd = sock->fd;
+               sock->fd = -1;
+               closesocket(manager, sock, fd);
+       }
+
+       LOCK(&manager->lock);
+
+       ISC_LIST_UNLINK(manager->socklist, sock, link);
+
+#ifdef ISC_PLATFORM_USETHREADS
+       if (ISC_LIST_EMPTY(manager->socklist))
+               SIGNAL(&manager->shutdown_ok);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       UNLOCK(&manager->lock);
+
+       free_socket(sockp);
+}
+
+static isc_result_t
+allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
+               isc_socket_t **socketp)
+{
+       isc_socket_t *sock;
+       isc_result_t result;
+       ISC_SOCKADDR_LEN_T cmsgbuflen;
+
+       sock = isc_mem_get(manager->mctx, sizeof(*sock));
+
+       if (sock == NULL)
+               return (ISC_R_NOMEMORY);
+
+       result = ISC_R_UNEXPECTED;
+
+       sock->magic = 0;
+       sock->references = 0;
+
+       sock->manager = manager;
+       sock->type = type;
+       sock->fd = -1;
+       sock->statsindex = NULL;
+
+       ISC_LINK_INIT(sock, link);
+
+       sock->recvcmsgbuf = NULL;
+       sock->sendcmsgbuf = NULL;
+
+       /*
+        * set up cmsg buffers
+        */
+       cmsgbuflen = 0;
+#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+       cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo));
+#endif
+#if defined(USE_CMSG) && defined(SO_TIMESTAMP)
+       cmsgbuflen += cmsg_space(sizeof(struct timeval));
+#endif
+       sock->recvcmsgbuflen = cmsgbuflen;
+       if (sock->recvcmsgbuflen != 0U) {
+               sock->recvcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen);
+               if (sock->recvcmsgbuf == NULL)
+                       goto error;
+       }
+
+       cmsgbuflen = 0;
+#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
+       cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo));
+#endif
+       sock->sendcmsgbuflen = cmsgbuflen;
+       if (sock->sendcmsgbuflen != 0U) {
+               sock->sendcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen);
+               if (sock->sendcmsgbuf == NULL)
+                       goto error;
+       }
+
+       memset(sock->name, 0, sizeof(sock->name));
+       sock->tag = NULL;
+
+       /*
+        * set up list of readers and writers to be initially empty
+        */
+       ISC_LIST_INIT(sock->recv_list);
+       ISC_LIST_INIT(sock->send_list);
+       ISC_LIST_INIT(sock->accept_list);
+       sock->connect_ev = NULL;
+       sock->pending_recv = 0;
+       sock->pending_send = 0;
+       sock->pending_accept = 0;
+       sock->listener = 0;
+       sock->connected = 0;
+       sock->connecting = 0;
+       sock->bound = 0;
+
+       /*
+        * initialize the lock
+        */
+       result = isc_mutex_init(&sock->lock);
+       if (result != ISC_R_SUCCESS) {
+               sock->magic = 0;
+               goto error;
+       }
+
+       /*
+        * Initialize readable and writable events
+        */
+       ISC_EVENT_INIT(&sock->readable_ev, sizeof(intev_t),
+                      ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTR,
+                      NULL, sock, sock, NULL, NULL);
+       ISC_EVENT_INIT(&sock->writable_ev, sizeof(intev_t),
+                      ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTW,
+                      NULL, sock, sock, NULL, NULL);
+
+       sock->magic = SOCKET_MAGIC;
+       *socketp = sock;
+
+       return (ISC_R_SUCCESS);
+
+ error:
+       if (sock->recvcmsgbuf != NULL)
+               isc_mem_put(manager->mctx, sock->recvcmsgbuf,
+                           sock->recvcmsgbuflen);
+       if (sock->sendcmsgbuf != NULL)
+               isc_mem_put(manager->mctx, sock->sendcmsgbuf,
+                           sock->sendcmsgbuflen);
+       isc_mem_put(manager->mctx, sock, sizeof(*sock));
+
+       return (result);
+}
+
+/*
+ * This event requires that the various lists be empty, that the reference
+ * count be 1, and that the magic number is valid.  The other socket bits,
+ * like the lock, must be initialized as well.  The fd associated must be
+ * marked as closed, by setting it to -1 on close, or this routine will
+ * also close the socket.
+ */
+static void
+free_socket(isc_socket_t **socketp) {
+       isc_socket_t *sock = *socketp;
+
+       INSIST(sock->references == 0);
+       INSIST(VALID_SOCKET(sock));
+       INSIST(!sock->connecting);
+       INSIST(!sock->pending_recv);
+       INSIST(!sock->pending_send);
+       INSIST(!sock->pending_accept);
+       INSIST(ISC_LIST_EMPTY(sock->recv_list));
+       INSIST(ISC_LIST_EMPTY(sock->send_list));
+       INSIST(ISC_LIST_EMPTY(sock->accept_list));
+       INSIST(!ISC_LINK_LINKED(sock, link));
+
+       if (sock->recvcmsgbuf != NULL)
+               isc_mem_put(sock->manager->mctx, sock->recvcmsgbuf,
+                           sock->recvcmsgbuflen);
+       if (sock->sendcmsgbuf != NULL)
+               isc_mem_put(sock->manager->mctx, sock->sendcmsgbuf,
+                           sock->sendcmsgbuflen);
+
+       sock->magic = 0;
+
+       DESTROYLOCK(&sock->lock);
+
+       isc_mem_put(sock->manager->mctx, sock, sizeof(*sock));
+
+       *socketp = NULL;
+}
+
+#ifdef SO_BSDCOMPAT
+/*
+ * This really should not be necessary to do.  Having to workout
+ * which kernel version we are on at run time so that we don't cause
+ * the kernel to issue a warning about us using a deprecated socket option.
+ * Such warnings should *never* be on by default in production kernels.
+ *
+ * We can't do this a build time because executables are moved between
+ * machines and hence kernels.
+ *
+ * We can't just not set SO_BSDCOMAT because some kernels require it.
+ */
+
+static isc_once_t         bsdcompat_once = ISC_ONCE_INIT;
+isc_boolean_t bsdcompat = ISC_TRUE;
+
+static void
+clear_bsdcompat(void) {
+#ifdef __linux__
+        struct utsname buf;
+        char *endp;
+        long int major;
+        long int minor;
+
+        uname(&buf);    /* Can only fail if buf is bad in Linux. */
+
+        /* Paranoia in parsing can be increased, but we trust uname(). */
+        major = strtol(buf.release, &endp, 10);
+        if (*endp == '.') {
+               minor = strtol(endp+1, &endp, 10);
+               if ((major > 2) || ((major == 2) && (minor >= 4))) {
+                       bsdcompat = ISC_FALSE;
+               }
+        }
+#endif /* __linux __ */
+}
+#endif
+
+static isc_result_t
+opensocket(isc_socketmgr_t *manager, isc_socket_t *sock) {
+       char strbuf[ISC_STRERRORSIZE];
+       const char *err = "socket";
+       int tries = 0;
+#if defined(USE_CMSG) || defined(SO_BSDCOMPAT)
+       int on = 1;
+#endif
+#if defined(SO_RCVBUF)
+       ISC_SOCKADDR_LEN_T optlen;
+       int size;
+#endif
+
+ again:
+       switch (sock->type) {
+       case isc_sockettype_udp:
+               sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP);
+               break;
+       case isc_sockettype_tcp:
+               sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP);
+               break;
+       case isc_sockettype_unix:
+               sock->fd = socket(sock->pf, SOCK_STREAM, 0);
+               break;
+       case isc_sockettype_fdwatch:
+               /*
+                * We should not be called for isc_sockettype_fdwatch sockets.
+                */
+               INSIST(0);
+               break;
+       }
+       if (sock->fd == -1 && errno == EINTR && tries++ < 42)
+               goto again;
+
+#ifdef F_DUPFD
+       /*
+        * Leave a space for stdio and TCP to work in.
+        */
+       if (manager->reserved != 0 && sock->type == isc_sockettype_udp &&
+           sock->fd >= 0 && sock->fd < manager->reserved) {
+               int new, tmp;
+               new = fcntl(sock->fd, F_DUPFD, manager->reserved);
+               tmp = errno;
+               (void)close(sock->fd);
+               errno = tmp;
+               sock->fd = new;
+               err = "isc_socket_create: fcntl/reserved";
+       } else if (sock->fd >= 0 && sock->fd < 20) {
+               int new, tmp;
+               new = fcntl(sock->fd, F_DUPFD, 20);
+               tmp = errno;
+               (void)close(sock->fd);
+               errno = tmp;
+               sock->fd = new;
+               err = "isc_socket_create: fcntl";
+       }
+#endif
+
+       if (sock->fd >= (int)manager->maxsocks) {
+               (void)close(sock->fd);
+               isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                              ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                              isc_msgcat, ISC_MSGSET_SOCKET,
+                              ISC_MSG_TOOMANYFDS,
+                              "socket: file descriptor exceeds limit (%d/%u)",
+                              sock->fd, manager->maxsocks);
+               return (ISC_R_NORESOURCES);
+       }
+
+       if (sock->fd < 0) {
+               switch (errno) {
+               case EMFILE:
+               case ENFILE:
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                                      isc_msgcat, ISC_MSGSET_SOCKET,
+                                      ISC_MSG_TOOMANYFDS,
+                                      "%s: %s", err, strbuf);
+                       /* fallthrough */
+               case ENOBUFS:
+                       return (ISC_R_NORESOURCES);
+
+               case EPROTONOSUPPORT:
+               case EPFNOSUPPORT:
+               case EAFNOSUPPORT:
+               /*
+                * Linux 2.2 (and maybe others) return EINVAL instead of
+                * EAFNOSUPPORT.
+                */
+               case EINVAL:
+                       return (ISC_R_FAMILYNOSUPPORT);
+
+               default:
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "%s() %s: %s", err,
+                                        isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_GENERAL,
+                                                       ISC_MSG_FAILED,
+                                                       "failed"),
+                                        strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+       }
+
+       if (make_nonblock(sock->fd) != ISC_R_SUCCESS) {
+               (void)close(sock->fd);
+               return (ISC_R_UNEXPECTED);
+       }
+
+#ifdef SO_BSDCOMPAT
+       RUNTIME_CHECK(isc_once_do(&bsdcompat_once,
+                                 clear_bsdcompat) == ISC_R_SUCCESS);
+       if (sock->type != isc_sockettype_unix && bsdcompat &&
+           setsockopt(sock->fd, SOL_SOCKET, SO_BSDCOMPAT,
+                      (void *)&on, sizeof(on)) < 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "setsockopt(%d, SO_BSDCOMPAT) %s: %s",
+                                sock->fd,
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"),
+                                strbuf);
+               /* Press on... */
+       }
+#endif
+
+#ifdef SO_NOSIGPIPE
+       if (setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE,
+                      (void *)&on, sizeof(on)) < 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "setsockopt(%d, SO_NOSIGPIPE) %s: %s",
+                                sock->fd,
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"),
+                                strbuf);
+               /* Press on... */
+       }
+#endif
+
+#if defined(USE_CMSG) || defined(SO_RCVBUF)
+       if (sock->type == isc_sockettype_udp) {
+
+#if defined(USE_CMSG)
+#if defined(SO_TIMESTAMP)
+               if (setsockopt(sock->fd, SOL_SOCKET, SO_TIMESTAMP,
+                              (void *)&on, sizeof(on)) < 0
+                   && errno != ENOPROTOOPT) {
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "setsockopt(%d, SO_TIMESTAMP) %s: %s",
+                                        sock->fd,
+                                        isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_GENERAL,
+                                                       ISC_MSG_FAILED,
+                                                       "failed"),
+                                        strbuf);
+                       /* Press on... */
+               }
+#endif /* SO_TIMESTAMP */
+
+#if defined(ISC_PLATFORM_HAVEIPV6)
+               if (sock->pf == AF_INET6 && sock->recvcmsgbuflen == 0U) {
+                       /*
+                        * Warn explicitly because this anomaly can be hidden
+                        * in usual operation (and unexpectedly appear later).
+                        */
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "No buffer available to receive "
+                                        "IPv6 destination");
+               }
+#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
+#ifdef IPV6_RECVPKTINFO
+               /* RFC 3542 */
+               if ((sock->pf == AF_INET6)
+                   && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                                  (void *)&on, sizeof(on)) < 0)) {
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "setsockopt(%d, IPV6_RECVPKTINFO) "
+                                        "%s: %s", sock->fd,
+                                        isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_GENERAL,
+                                                       ISC_MSG_FAILED,
+                                                       "failed"),
+                                        strbuf);
+               }
+#else
+               /* RFC 2292 */
+               if ((sock->pf == AF_INET6)
+                   && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO,
+                                  (void *)&on, sizeof(on)) < 0)) {
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "setsockopt(%d, IPV6_PKTINFO) %s: %s",
+                                        sock->fd,
+                                        isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_GENERAL,
+                                                       ISC_MSG_FAILED,
+                                                       "failed"),
+                                        strbuf);
+               }
+#endif /* IPV6_RECVPKTINFO */
+#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
+#ifdef IPV6_USE_MIN_MTU        /* RFC 3542, not too common yet*/
+               /* use minimum MTU */
+               if (sock->pf == AF_INET6) {
+                       (void)setsockopt(sock->fd, IPPROTO_IPV6,
+                                        IPV6_USE_MIN_MTU,
+                                        (void *)&on, sizeof(on));
+               }
+#endif
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+#endif /* defined(USE_CMSG) */
+
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+               /*
+                * Turn off Path MTU discovery on IPv4/UDP sockets.
+                */
+               if (sock->pf == AF_INET) {
+                       int action = IP_PMTUDISC_DONT;
+                       (void)setsockopt(sock->fd, IPPROTO_IP, IP_MTU_DISCOVER,
+                                        &action, sizeof(action));
+               }
+#endif
+#if defined(IP_DONTFRAG)
+               /*
+                * Turn off Path MTU discovery on IPv4/UDP sockets.
+                */
+               if (sock->pf == AF_INET) {
+                       int off = 0;
+                       (void)setsockopt(sock->fd, IPPROTO_IP, IP_DONTFRAG,
+                                        &off, sizeof(off));
+               }
+#endif
+
+#if defined(SO_RCVBUF)
+               optlen = sizeof(size);
+               if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+                              (void *)&size, &optlen) >= 0 &&
+                    size < RCVBUFSIZE) {
+                       size = RCVBUFSIZE;
+                       if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+                                      (void *)&size, sizeof(size)) == -1) {
+                               isc__strerror(errno, strbuf, sizeof(strbuf));
+                               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                       "setsockopt(%d, SO_RCVBUF, %d) %s: %s",
+                                       sock->fd, size,
+                                       isc_msgcat_get(isc_msgcat,
+                                                      ISC_MSGSET_GENERAL,
+                                                      ISC_MSG_FAILED,
+                                                      "failed"),
+                                       strbuf);
+                       }
+               }
+#endif
+       }
+#endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */
+
+       inc_stats(manager->stats, sock->statsindex[STATID_OPEN]);
+
+       return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Create a new 'type' socket managed by 'manager'.  Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value.  The new socket is returned
+ * in 'socketp'.
+ */
+isc_result_t
+isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
+                 isc_socket_t **socketp)
+{
+       isc_socket_t *sock = NULL;
+       isc_result_t result;
+       int lockid;
+
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(socketp != NULL && *socketp == NULL);
+       REQUIRE(type != isc_sockettype_fdwatch);
+
+       result = allocate_socket(manager, type, &sock);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       switch (sock->type) {
+       case isc_sockettype_udp:
+               sock->statsindex =
+                       (pf == AF_INET) ? upd4statsindex : upd6statsindex;
+               break;
+       case isc_sockettype_tcp:
+               sock->statsindex =
+                       (pf == AF_INET) ? tcp4statsindex : tcp6statsindex;
+               break;
+       case isc_sockettype_unix:
+               sock->statsindex = unixstatsindex;
+               break;
+       default:
+               INSIST(0);
+       }
+
+       sock->pf = pf;
+       result = opensocket(manager, sock);
+       if (result != ISC_R_SUCCESS) {
+               inc_stats(manager->stats, sock->statsindex[STATID_OPENFAIL]);
+               free_socket(&sock);
+               return (result);
+       }
+
+       sock->references = 1;
+       *socketp = sock;
+
+       /*
+        * Note we don't have to lock the socket like we normally would because
+        * there are no external references to it yet.
+        */
+
+       lockid = FDLOCK_ID(sock->fd);
+       LOCK(&manager->fdlock[lockid]);
+       manager->fds[sock->fd] = sock;
+       manager->fdstate[sock->fd] = MANAGED;
+#ifdef USE_DEVPOLL
+       INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 &&
+              sock->manager->fdpollinfo[sock->fd].want_write == 0);
+#endif
+       UNLOCK(&manager->fdlock[lockid]);
+
+       LOCK(&manager->lock);
+       ISC_LIST_APPEND(manager->socklist, sock, link);
+#ifdef USE_SELECT
+       if (manager->maxfd < sock->fd)
+               manager->maxfd = sock->fd;
+#endif
+       UNLOCK(&manager->lock);
+
+       socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+                  ISC_MSG_CREATED, "created");
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_open(isc_socket_t *sock) {
+       isc_result_t result;
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       REQUIRE(sock->references == 1);
+       REQUIRE(sock->type != isc_sockettype_fdwatch);
+       UNLOCK(&sock->lock);
+       /*
+        * We don't need to retain the lock hereafter, since no one else has
+        * this socket.
+        */
+       REQUIRE(sock->fd == -1);
+
+       result = opensocket(sock->manager, sock);
+       if (result != ISC_R_SUCCESS)
+               sock->fd = -1;
+
+       if (result == ISC_R_SUCCESS) {
+               int lockid = FDLOCK_ID(sock->fd);
+
+               LOCK(&sock->manager->fdlock[lockid]);
+               sock->manager->fds[sock->fd] = sock;
+               sock->manager->fdstate[sock->fd] = MANAGED;
+#ifdef USE_DEVPOLL
+               INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 &&
+                      sock->manager->fdpollinfo[sock->fd].want_write == 0);
+#endif
+               UNLOCK(&sock->manager->fdlock[lockid]);
+
+#ifdef USE_SELECT
+               LOCK(&sock->manager->lock);
+               if (sock->manager->maxfd < sock->fd)
+                       sock->manager->maxfd = sock->fd;
+               UNLOCK(&sock->manager->lock);
+#endif
+       }
+
+       return (result);
+}
+
+/*
+ * Create a new 'type' socket managed by 'manager'.  Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value.  The new socket is returned
+ * in 'socketp'.
+ */
+isc_result_t
+isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags,
+                        isc_sockfdwatch_t callback, void *cbarg,
+                        isc_task_t *task, isc_socket_t **socketp)
+{
+       isc_socket_t *sock = NULL;
+       isc_result_t result;
+       int lockid;
+
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(socketp != NULL && *socketp == NULL);
+
+       result = allocate_socket(manager, isc_sockettype_fdwatch, &sock);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       sock->fd = fd;
+       sock->fdwatcharg = cbarg;
+       sock->fdwatchcb = callback;
+       sock->fdwatchflags = flags;
+       sock->fdwatchtask = task;
+       sock->statsindex = fdwatchstatsindex;
+
+       sock->references = 1;
+       *socketp = sock;
+
+       /*
+        * Note we don't have to lock the socket like we normally would because
+        * there are no external references to it yet.
+        */
+
+       lockid = FDLOCK_ID(sock->fd);
+       LOCK(&manager->fdlock[lockid]);
+       manager->fds[sock->fd] = sock;
+       manager->fdstate[sock->fd] = MANAGED;
+       UNLOCK(&manager->fdlock[lockid]);
+
+       LOCK(&manager->lock);
+       ISC_LIST_APPEND(manager->socklist, sock, link);
+#ifdef USE_SELECT
+       if (manager->maxfd < sock->fd)
+               manager->maxfd = sock->fd;
+#endif
+       UNLOCK(&manager->lock);
+
+       if (flags & ISC_SOCKFDWATCH_READ)
+               select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+       if (flags & ISC_SOCKFDWATCH_WRITE)
+               select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
+
+       socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+                  ISC_MSG_CREATED, "fdwatch-created");
+
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * Attach to a socket.  Caller must explicitly detach when it is done.
+ */
+void
+isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(socketp != NULL && *socketp == NULL);
+
+       LOCK(&sock->lock);
+       sock->references++;
+       UNLOCK(&sock->lock);
+
+       *socketp = sock;
+}
+
+/*
+ * Dereference a socket.  If this is the last reference to it, clean things
+ * up by destroying the socket.
+ */
+void
+isc_socket_detach(isc_socket_t **socketp) {
+       isc_socket_t *sock;
+       isc_boolean_t kill_socket = ISC_FALSE;
+
+       REQUIRE(socketp != NULL);
+       sock = *socketp;
+       REQUIRE(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       REQUIRE(sock->references > 0);
+       sock->references--;
+       if (sock->references == 0)
+               kill_socket = ISC_TRUE;
+       UNLOCK(&sock->lock);
+
+       if (kill_socket)
+               destroy(&sock);
+
+       *socketp = NULL;
+}
+
+isc_result_t
+isc_socket_close(isc_socket_t *sock) {
+       int fd;
+       isc_socketmgr_t *manager;
+       isc_sockettype_t type;
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+
+       REQUIRE(sock->references == 1);
+       REQUIRE(sock->type != isc_sockettype_fdwatch);
+       REQUIRE(sock->fd >= 0 && sock->fd < (int)sock->manager->maxsocks);
+
+       INSIST(!sock->connecting);
+       INSIST(!sock->pending_recv);
+       INSIST(!sock->pending_send);
+       INSIST(!sock->pending_accept);
+       INSIST(ISC_LIST_EMPTY(sock->recv_list));
+       INSIST(ISC_LIST_EMPTY(sock->send_list));
+       INSIST(ISC_LIST_EMPTY(sock->accept_list));
+       INSIST(sock->connect_ev == NULL);
+
+       manager = sock->manager;
+       type = sock->type;
+       fd = sock->fd;
+       sock->fd = -1;
+       memset(sock->name, 0, sizeof(sock->name));
+       sock->tag = NULL;
+       sock->listener = 0;
+       sock->connected = 0;
+       sock->connecting = 0;
+       sock->bound = 0;
+       isc_sockaddr_any(&sock->peer_address);
+
+       UNLOCK(&sock->lock);
+
+       closesocket(manager, sock, fd);
+
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * I/O is possible on a given socket.  Schedule an event to this task that
+ * will call an internal function to do the I/O.  This will charge the
+ * task with the I/O operation and let our select loop handler get back
+ * to doing something real as fast as possible.
+ *
+ * The socket and manager must be locked before calling this function.
+ */
+static void
+dispatch_recv(isc_socket_t *sock) {
+       intev_t *iev;
+       isc_socketevent_t *ev;
+       isc_task_t *sender;
+
+       INSIST(!sock->pending_recv);
+
+       if (sock->type != isc_sockettype_fdwatch) {
+               ev = ISC_LIST_HEAD(sock->recv_list);
+               if (ev == NULL)
+                       return;
+               socket_log(sock, NULL, EVENT, NULL, 0, 0,
+                          "dispatch_recv:  event %p -> task %p",
+                          ev, ev->ev_sender);
+               sender = ev->ev_sender;
+       } else {
+               sender = sock->fdwatchtask;
+       }
+
+       sock->pending_recv = 1;
+       iev = &sock->readable_ev;
+
+       sock->references++;
+       iev->ev_sender = sock;
+       if (sock->type == isc_sockettype_fdwatch)
+               iev->ev_action = internal_fdwatch_read;
+       else
+               iev->ev_action = internal_recv;
+       iev->ev_arg = sock;
+
+       isc_task_send(sender, (isc_event_t **)&iev);
+}
+
+static void
+dispatch_send(isc_socket_t *sock) {
+       intev_t *iev;
+       isc_socketevent_t *ev;
+       isc_task_t *sender;
+
+       INSIST(!sock->pending_send);
+
+       if (sock->type != isc_sockettype_fdwatch) {
+               ev = ISC_LIST_HEAD(sock->send_list);
+               if (ev == NULL)
+                       return;
+               socket_log(sock, NULL, EVENT, NULL, 0, 0,
+                          "dispatch_send:  event %p -> task %p",
+                          ev, ev->ev_sender);
+               sender = ev->ev_sender;
+       } else {
+               sender = sock->fdwatchtask;
+       }
+
+       sock->pending_send = 1;
+       iev = &sock->writable_ev;
+
+       sock->references++;
+       iev->ev_sender = sock;
+       if (sock->type == isc_sockettype_fdwatch)
+               iev->ev_action = internal_fdwatch_write;
+       else
+               iev->ev_action = internal_send;
+       iev->ev_arg = sock;
+
+       isc_task_send(sender, (isc_event_t **)&iev);
+}
+
+/*
+ * Dispatch an internal accept event.
+ */
+static void
+dispatch_accept(isc_socket_t *sock) {
+       intev_t *iev;
+       isc_socket_newconnev_t *ev;
+
+       INSIST(!sock->pending_accept);
+
+       /*
+        * Are there any done events left, or were they all canceled
+        * before the manager got the socket lock?
+        */
+       ev = ISC_LIST_HEAD(sock->accept_list);
+       if (ev == NULL)
+               return;
+
+       sock->pending_accept = 1;
+       iev = &sock->readable_ev;
+
+       sock->references++;  /* keep socket around for this internal event */
+       iev->ev_sender = sock;
+       iev->ev_action = internal_accept;
+       iev->ev_arg = sock;
+
+       isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+}
+
+static void
+dispatch_connect(isc_socket_t *sock) {
+       intev_t *iev;
+       isc_socket_connev_t *ev;
+
+       iev = &sock->writable_ev;
+
+       ev = sock->connect_ev;
+       INSIST(ev != NULL); /* XXX */
+
+       INSIST(sock->connecting);
+
+       sock->references++;  /* keep socket around for this internal event */
+       iev->ev_sender = sock;
+       iev->ev_action = internal_connect;
+       iev->ev_arg = sock;
+
+       isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+}
+
+/*
+ * Dequeue an item off the given socket's read queue, set the result code
+ * in the done event to the one provided, and send it to the task it was
+ * destined for.
+ *
+ * If the event to be sent is on a list, remove it before sending.  If
+ * asked to, send and detach from the socket as well.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+       isc_task_t *task;
+
+       task = (*dev)->ev_sender;
+
+       (*dev)->ev_sender = sock;
+
+       if (ISC_LINK_LINKED(*dev, ev_link))
+               ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
+
+       if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+           == ISC_SOCKEVENTATTR_ATTACHED)
+               isc_task_sendanddetach(&task, (isc_event_t **)dev);
+       else
+               isc_task_send(task, (isc_event_t **)dev);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+       isc_task_t *task;
+
+       INSIST(dev != NULL && *dev != NULL);
+
+       task = (*dev)->ev_sender;
+       (*dev)->ev_sender = sock;
+
+       if (ISC_LINK_LINKED(*dev, ev_link))
+               ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
+
+       if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+           == ISC_SOCKEVENTATTR_ATTACHED)
+               isc_task_sendanddetach(&task, (isc_event_t **)dev);
+       else
+               isc_task_send(task, (isc_event_t **)dev);
+}
+
+/*
+ * Call accept() on a socket, to get the new file descriptor.  The listen
+ * socket is used as a prototype to create a new isc_socket_t.  The new
+ * socket has one outstanding reference.  The task receiving the event
+ * will be detached from just after the event is delivered.
+ *
+ * On entry to this function, the event delivered is the internal
+ * readable event, and the first item on the accept_list should be
+ * the done event we want to send.  If the list is empty, this is a no-op,
+ * so just unlock and return.
+ */
+static void
+internal_accept(isc_task_t *me, isc_event_t *ev) {
+       isc_socket_t *sock;
+       isc_socketmgr_t *manager;
+       isc_socket_newconnev_t *dev;
+       isc_task_t *task;
+       ISC_SOCKADDR_LEN_T addrlen;
+       int fd;
+       isc_result_t result = ISC_R_SUCCESS;
+       char strbuf[ISC_STRERRORSIZE];
+       const char *err = "accept";
+
+       UNUSED(me);
+
+       sock = ev->ev_sender;
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       socket_log(sock, NULL, TRACE,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+                  "internal_accept called, locked socket");
+
+       manager = sock->manager;
+       INSIST(VALID_MANAGER(manager));
+
+       INSIST(sock->listener);
+       INSIST(sock->pending_accept == 1);
+       sock->pending_accept = 0;
+
+       INSIST(sock->references > 0);
+       sock->references--;  /* the internal event is done with this socket */
+       if (sock->references == 0) {
+               UNLOCK(&sock->lock);
+               destroy(&sock);
+               return;
+       }
+
+       /*
+        * Get the first item off the accept list.
+        * If it is empty, unlock the socket and return.
+        */
+       dev = ISC_LIST_HEAD(sock->accept_list);
+       if (dev == NULL) {
+               UNLOCK(&sock->lock);
+               return;
+       }
+
+       /*
+        * Try to accept the new connection.  If the accept fails with
+        * EAGAIN or EINTR, simply poke the watcher to watch this socket
+        * again.  Also ignore ECONNRESET, which has been reported to
+        * be spuriously returned on Linux 2.2.19 although it is not
+        * a documented error for accept().  ECONNABORTED has been
+        * reported for Solaris 8.  The rest are thrown in not because
+        * we have seen them but because they are ignored by other
+        * daemons such as BIND 8 and Apache.
+        */
+
+       addrlen = sizeof(dev->newsocket->peer_address.type);
+       memset(&dev->newsocket->peer_address.type, 0, addrlen);
+       fd = accept(sock->fd, &dev->newsocket->peer_address.type.sa,
+                   (void *)&addrlen);
+
+#ifdef F_DUPFD
+       /*
+        * Leave a space for stdio to work in.
+        */
+       if (fd >= 0 && fd < 20) {
+               int new, tmp;
+               new = fcntl(fd, F_DUPFD, 20);
+               tmp = errno;
+               (void)close(fd);
+               errno = tmp;
+               fd = new;
+               err = "accept/fcntl";
+       }
+#endif
+
+       if (fd < 0) {
+               if (SOFT_ERROR(errno))
+                       goto soft_error;
+               switch (errno) {
+               case ENFILE:
+               case EMFILE:
+                       isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                                      isc_msgcat, ISC_MSGSET_SOCKET,
+                                      ISC_MSG_TOOMANYFDS,
+                                      "%s: too many open file descriptors",
+                                      err);
+                       goto soft_error;
+
+               case ENOBUFS:
+               case ENOMEM:
+               case ECONNRESET:
+               case ECONNABORTED:
+               case EHOSTUNREACH:
+               case EHOSTDOWN:
+               case ENETUNREACH:
+               case ENETDOWN:
+               case ECONNREFUSED:
+#ifdef EPROTO
+               case EPROTO:
+#endif
+#ifdef ENONET
+               case ENONET:
+#endif
+                       goto soft_error;
+               default:
+                       break;
+               }
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "internal_accept: %s() %s: %s", err,
+                                isc_msgcat_get(isc_msgcat,
+                                               ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED,
+                                               "failed"),
+                                strbuf);
+               fd = -1;
+               result = ISC_R_UNEXPECTED;
+       } else {
+               if (addrlen == 0U) {
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "internal_accept(): "
+                                        "accept() failed to return "
+                                        "remote address");
+
+                       (void)close(fd);
+                       goto soft_error;
+               } else if (dev->newsocket->peer_address.type.sa.sa_family !=
+                          sock->pf)
+               {
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "internal_accept(): "
+                                        "accept() returned peer address "
+                                        "family %u (expected %u)",
+                                        dev->newsocket->peer_address.
+                                        type.sa.sa_family,
+                                        sock->pf);
+                       (void)close(fd);
+                       goto soft_error;
+               } else if (fd >= (int)manager->maxsocks) {
+                       isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                                      isc_msgcat, ISC_MSGSET_SOCKET,
+                                      ISC_MSG_TOOMANYFDS,
+                                      "accept: "
+                                      "file descriptor exceeds limit (%d/%u)",
+                                      fd, manager->maxsocks);
+                       (void)close(fd);
+                       goto soft_error;
+               }
+       }
+
+       if (fd != -1) {
+               dev->newsocket->peer_address.length = addrlen;
+               dev->newsocket->pf = sock->pf;
+       }
+
+       /*
+        * Pull off the done event.
+        */
+       ISC_LIST_UNLINK(sock->accept_list, dev, ev_link);
+
+       /*
+        * Poke watcher if there are more pending accepts.
+        */
+       if (!ISC_LIST_EMPTY(sock->accept_list))
+               select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
+
+       UNLOCK(&sock->lock);
+
+       if (fd != -1 && (make_nonblock(fd) != ISC_R_SUCCESS)) {
+               (void)close(fd);
+               fd = -1;
+               result = ISC_R_UNEXPECTED;
+       }
+
+       /*
+        * -1 means the new socket didn't happen.
+        */
+       if (fd != -1) {
+               int lockid = FDLOCK_ID(fd);
+
+               LOCK(&manager->fdlock[lockid]);
+               manager->fds[fd] = dev->newsocket;
+               manager->fdstate[fd] = MANAGED;
+               UNLOCK(&manager->fdlock[lockid]);
+
+               LOCK(&manager->lock);
+               ISC_LIST_APPEND(manager->socklist, dev->newsocket, link);
+
+               dev->newsocket->fd = fd;
+               dev->newsocket->bound = 1;
+               dev->newsocket->connected = 1;
+
+               /*
+                * Save away the remote address
+                */
+               dev->address = dev->newsocket->peer_address;
+
+#ifdef USE_SELECT
+               if (manager->maxfd < fd)
+                       manager->maxfd = fd;
+#endif
+
+               socket_log(sock, &dev->newsocket->peer_address, CREATION,
+                          isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
+                          "accepted connection, new socket %p",
+                          dev->newsocket);
+
+               UNLOCK(&manager->lock);
+
+               inc_stats(manager->stats, sock->statsindex[STATID_ACCEPT]);
+       } else {
+               inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]);
+               dev->newsocket->references--;
+               free_socket(&dev->newsocket);
+       }
+
+       /*
+        * Fill in the done event details and send it off.
+        */
+       dev->result = result;
+       task = dev->ev_sender;
+       dev->ev_sender = sock;
+
+       isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev));
+       return;
+
+ soft_error:
+       select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
+       UNLOCK(&sock->lock);
+
+       inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]);
+       return;
+}
+
+static void
+internal_recv(isc_task_t *me, isc_event_t *ev) {
+       isc_socketevent_t *dev;
+       isc_socket_t *sock;
+
+       INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
+
+       sock = ev->ev_sender;
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       socket_log(sock, NULL, IOEVENT,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
+                  "internal_recv: task %p got event %p", me, ev);
+
+       INSIST(sock->pending_recv == 1);
+       sock->pending_recv = 0;
+
+       INSIST(sock->references > 0);
+       sock->references--;  /* the internal event is done with this socket */
+       if (sock->references == 0) {
+               UNLOCK(&sock->lock);
+               destroy(&sock);
+               return;
+       }
+
+       /*
+        * Try to do as much I/O as possible on this socket.  There are no
+        * limits here, currently.
+        */
+       dev = ISC_LIST_HEAD(sock->recv_list);
+       while (dev != NULL) {
+               switch (doio_recv(sock, dev)) {
+               case DOIO_SOFT:
+                       goto poke;
+
+               case DOIO_EOF:
+                       /*
+                        * read of 0 means the remote end was closed.
+                        * Run through the event queue and dispatch all
+                        * the events with an EOF result code.
+                        */
+                       do {
+                               dev->result = ISC_R_EOF;
+                               send_recvdone_event(sock, &dev);
+                               dev = ISC_LIST_HEAD(sock->recv_list);
+                       } while (dev != NULL);
+                       goto poke;
+
+               case DOIO_SUCCESS:
+               case DOIO_HARD:
+                       send_recvdone_event(sock, &dev);
+                       break;
+               }
+
+               dev = ISC_LIST_HEAD(sock->recv_list);
+       }
+
+ poke:
+       if (!ISC_LIST_EMPTY(sock->recv_list))
+               select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+
+       UNLOCK(&sock->lock);
+}
+
+static void
+internal_send(isc_task_t *me, isc_event_t *ev) {
+       isc_socketevent_t *dev;
+       isc_socket_t *sock;
+
+       INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
+
+       /*
+        * Find out what socket this is and lock it.
+        */
+       sock = (isc_socket_t *)ev->ev_sender;
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       socket_log(sock, NULL, IOEVENT,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
+                  "internal_send: task %p got event %p", me, ev);
+
+       INSIST(sock->pending_send == 1);
+       sock->pending_send = 0;
+
+       INSIST(sock->references > 0);
+       sock->references--;  /* the internal event is done with this socket */
+       if (sock->references == 0) {
+               UNLOCK(&sock->lock);
+               destroy(&sock);
+               return;
+       }
+
+       /*
+        * Try to do as much I/O as possible on this socket.  There are no
+        * limits here, currently.
+        */
+       dev = ISC_LIST_HEAD(sock->send_list);
+       while (dev != NULL) {
+               switch (doio_send(sock, dev)) {
+               case DOIO_SOFT:
+                       goto poke;
+
+               case DOIO_HARD:
+               case DOIO_SUCCESS:
+                       send_senddone_event(sock, &dev);
+                       break;
+               }
+
+               dev = ISC_LIST_HEAD(sock->send_list);
+       }
+
+ poke:
+       if (!ISC_LIST_EMPTY(sock->send_list))
+               select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
+
+       UNLOCK(&sock->lock);
+}
+
+static void
+internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) {
+       isc_socket_t *sock;
+       int more_data;
+
+       INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
+
+       /*
+        * Find out what socket this is and lock it.
+        */
+       sock = (isc_socket_t *)ev->ev_sender;
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       socket_log(sock, NULL, IOEVENT,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
+                  "internal_fdwatch_write: task %p got event %p", me, ev);
+
+       INSIST(sock->pending_send == 1);
+
+       UNLOCK(&sock->lock);
+       more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg);
+       LOCK(&sock->lock);
+
+       sock->pending_send = 0;
+
+       INSIST(sock->references > 0);
+       sock->references--;  /* the internal event is done with this socket */
+       if (sock->references == 0) {
+               UNLOCK(&sock->lock);
+               destroy(&sock);
+               return;
+       }
+
+       if (more_data)
+               select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
+
+       UNLOCK(&sock->lock);
+}
+
+static void
+internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) {
+       isc_socket_t *sock;
+       int more_data;
+
+       INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
+
+       /*
+        * Find out what socket this is and lock it.
+        */
+       sock = (isc_socket_t *)ev->ev_sender;
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       socket_log(sock, NULL, IOEVENT,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
+                  "internal_fdwatch_read: task %p got event %p", me, ev);
+
+       INSIST(sock->pending_recv == 1);
+
+       UNLOCK(&sock->lock);
+       more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg);
+       LOCK(&sock->lock);
+
+       sock->pending_recv = 0;
+
+       INSIST(sock->references > 0);
+       sock->references--;  /* the internal event is done with this socket */
+       if (sock->references == 0) {
+               UNLOCK(&sock->lock);
+               destroy(&sock);
+               return;
+       }
+
+       if (more_data)
+               select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+
+       UNLOCK(&sock->lock);
+}
+
+/*
+ * Process read/writes on each fd here.  Avoid locking
+ * and unlocking twice if both reads and writes are possible.
+ */
+static void
+process_fd(isc_socketmgr_t *manager, int fd, isc_boolean_t readable,
+          isc_boolean_t writeable)
+{
+       isc_socket_t *sock;
+       isc_boolean_t unlock_sock;
+       isc_boolean_t unwatch_read = ISC_FALSE, unwatch_write = ISC_FALSE;
+       int lockid = FDLOCK_ID(fd);
+
+       /*
+        * If the socket is going to be closed, don't do more I/O.
+        */
+       LOCK(&manager->fdlock[lockid]);
+       if (manager->fdstate[fd] == CLOSE_PENDING) {
+               UNLOCK(&manager->fdlock[lockid]);
+
+               (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+               (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+               return;
+       }
+
+       sock = manager->fds[fd];
+       unlock_sock = ISC_FALSE;
+       if (readable) {
+               if (sock == NULL) {
+                       unwatch_read = ISC_TRUE;
+                       goto check_write;
+               }
+               unlock_sock = ISC_TRUE;
+               LOCK(&sock->lock);
+               if (!SOCK_DEAD(sock)) {
+                       if (sock->listener)
+                               dispatch_accept(sock);
+                       else
+                               dispatch_recv(sock);
+               }
+               unwatch_read = ISC_TRUE;
+       }
+check_write:
+       if (writeable) {
+               if (sock == NULL) {
+                       unwatch_write = ISC_TRUE;
+                       goto unlock_fd;
+               }
+               if (!unlock_sock) {
+                       unlock_sock = ISC_TRUE;
+                       LOCK(&sock->lock);
+               }
+               if (!SOCK_DEAD(sock)) {
+                       if (sock->connecting)
+                               dispatch_connect(sock);
+                       else
+                               dispatch_send(sock);
+               }
+               unwatch_write = ISC_TRUE;
+       }
+       if (unlock_sock)
+               UNLOCK(&sock->lock);
+
+ unlock_fd:
+       UNLOCK(&manager->fdlock[lockid]);
+       if (unwatch_read)
+               (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+       if (unwatch_write)
+               (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+
+}
+
+#ifdef USE_KQUEUE
+static isc_boolean_t
+process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) {
+       int i;
+       isc_boolean_t readable, writable;
+       isc_boolean_t done = ISC_FALSE;
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_boolean_t have_ctlevent = ISC_FALSE;
+#endif
+
+       if (nevents == manager->nevents) {
+               /*
+                * This is not an error, but something unexpected.  If this
+                * happens, it may indicate the need for increasing
+                * ISC_SOCKET_MAXEVENTS.
+                */
+               manager_log(manager, ISC_LOGCATEGORY_GENERAL,
+                           ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,
+                           "maximum number of FD events (%d) received",
+                           nevents);
+       }
+
+       for (i = 0; i < nevents; i++) {
+               REQUIRE(events[i].ident < manager->maxsocks);
+#ifdef ISC_PLATFORM_USETHREADS
+               if (events[i].ident == (uintptr_t)manager->pipe_fds[0]) {
+                       have_ctlevent = ISC_TRUE;
+                       continue;
+               }
+#endif
+               readable = ISC_TF(events[i].filter == EVFILT_READ);
+               writable = ISC_TF(events[i].filter == EVFILT_WRITE);
+               process_fd(manager, events[i].ident, readable, writable);
+       }
+
+#ifdef ISC_PLATFORM_USETHREADS
+       if (have_ctlevent)
+               done = process_ctlfd(manager);
+#endif
+
+       return (done);
+}
+#elif defined(USE_EPOLL)
+static isc_boolean_t
+process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) {
+       int i;
+       isc_boolean_t done = ISC_FALSE;
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_boolean_t have_ctlevent = ISC_FALSE;
+#endif
+
+       if (nevents == manager->nevents) {
+               manager_log(manager, ISC_LOGCATEGORY_GENERAL,
+                           ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,
+                           "maximum number of FD events (%d) received",
+                           nevents);
+       }
+
+       for (i = 0; i < nevents; i++) {
+               REQUIRE(events[i].data.fd < (int)manager->maxsocks);
+#ifdef ISC_PLATFORM_USETHREADS
+               if (events[i].data.fd == manager->pipe_fds[0]) {
+                       have_ctlevent = ISC_TRUE;
+                       continue;
+               }
+#endif
+               if ((events[i].events & EPOLLERR) != 0 ||
+                   (events[i].events & EPOLLHUP) != 0) {
+                       /*
+                        * epoll does not set IN/OUT bits on an erroneous
+                        * condition, so we need to try both anyway.  This is a
+                        * bit inefficient, but should be okay for such rare
+                        * events.  Note also that the read or write attempt
+                        * won't block because we use non-blocking sockets.
+                        */
+                       events[i].events |= (EPOLLIN | EPOLLOUT);
+               }
+               process_fd(manager, events[i].data.fd,
+                          (events[i].events & EPOLLIN) != 0,
+                          (events[i].events & EPOLLOUT) != 0);
+       }
+
+#ifdef ISC_PLATFORM_USETHREADS
+       if (have_ctlevent)
+               done = process_ctlfd(manager);
+#endif
+
+       return (done);
+}
+#elif defined(USE_DEVPOLL)
+static isc_boolean_t
+process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) {
+       int i;
+       isc_boolean_t done = ISC_FALSE;
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_boolean_t have_ctlevent = ISC_FALSE;
+#endif
+
+       if (nevents == manager->nevents) {
+               manager_log(manager, ISC_LOGCATEGORY_GENERAL,
+                           ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,
+                           "maximum number of FD events (%d) received",
+                           nevents);
+       }
+
+       for (i = 0; i < nevents; i++) {
+               REQUIRE(events[i].fd < (int)manager->maxsocks);
+#ifdef ISC_PLATFORM_USETHREADS
+               if (events[i].fd == manager->pipe_fds[0]) {
+                       have_ctlevent = ISC_TRUE;
+                       continue;
+               }
+#endif
+               process_fd(manager, events[i].fd,
+                          (events[i].events & POLLIN) != 0,
+                          (events[i].events & POLLOUT) != 0);
+       }
+
+#ifdef ISC_PLATFORM_USETHREADS
+       if (have_ctlevent)
+               done = process_ctlfd(manager);
+#endif
+
+       return (done);
+}
+#elif defined(USE_SELECT)
+static void
+process_fds(isc_socketmgr_t *manager, int maxfd,
+           fd_set *readfds, fd_set *writefds)
+{
+       int i;
+
+       REQUIRE(maxfd <= (int)manager->maxsocks);
+
+       for (i = 0; i < maxfd; i++) {
+#ifdef ISC_PLATFORM_USETHREADS
+               if (i == manager->pipe_fds[0] || i == manager->pipe_fds[1])
+                       continue;
+#endif /* ISC_PLATFORM_USETHREADS */
+               process_fd(manager, i, FD_ISSET(i, readfds),
+                          FD_ISSET(i, writefds));
+       }
+}
+#endif
+
+#ifdef ISC_PLATFORM_USETHREADS
+static isc_boolean_t
+process_ctlfd(isc_socketmgr_t *manager) {
+       int msg, fd;
+
+       for (;;) {
+               select_readmsg(manager, &fd, &msg);
+
+               manager_log(manager, IOEVENT,
+                           isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                                          ISC_MSG_WATCHERMSG,
+                                          "watcher got message %d "
+                                          "for socket %d"), msg, fd);
+
+               /*
+                * Nothing to read?
+                */
+               if (msg == SELECT_POKE_NOTHING)
+                       break;
+
+               /*
+                * Handle shutdown message.  We really should
+                * jump out of this loop right away, but
+                * it doesn't matter if we have to do a little
+                * more work first.
+                */
+               if (msg == SELECT_POKE_SHUTDOWN)
+                       return (ISC_TRUE);
+
+               /*
+                * This is a wakeup on a socket.  Look
+                * at the event queue for both read and write,
+                * and decide if we need to watch on it now
+                * or not.
+                */
+               wakeup_socket(manager, fd, msg);
+       }
+
+       return (ISC_FALSE);
+}
+
+/*
+ * This is the thread that will loop forever, always in a select or poll
+ * call.
+ *
+ * When select returns something to do, track down what thread gets to do
+ * this I/O and post the event to it.
+ */
+static isc_threadresult_t
+watcher(void *uap) {
+       isc_socketmgr_t *manager = uap;
+       isc_boolean_t done;
+       int ctlfd;
+       int cc;
+#ifdef USE_KQUEUE
+       const char *fnname = "kevent()";
+#elif defined (USE_EPOLL)
+       const char *fnname = "epoll_wait()";
+#elif defined(USE_DEVPOLL)
+       const char *fnname = "ioctl(DP_POLL)";
+       struct dvpoll dvp;
+#elif defined (USE_SELECT)
+       const char *fnname = "select()";
+       int maxfd;
+#endif
+       char strbuf[ISC_STRERRORSIZE];
+#ifdef ISC_SOCKET_USE_POLLWATCH
+       pollstate_t pollstate = poll_idle;
+#endif
+
+       /*
+        * Get the control fd here.  This will never change.
+        */
+       ctlfd = manager->pipe_fds[0];
+       done = ISC_FALSE;
+       while (!done) {
+               do {
+#ifdef USE_KQUEUE
+                       cc = kevent(manager->kqueue_fd, NULL, 0,
+                                   manager->events, manager->nevents, NULL);
+#elif defined(USE_EPOLL)
+                       cc = epoll_wait(manager->epoll_fd, manager->events,
+                                       manager->nevents, -1);
+#elif defined(USE_DEVPOLL)
+                       dvp.dp_fds = manager->events;
+                       dvp.dp_nfds = manager->nevents;
+#ifndef ISC_SOCKET_USE_POLLWATCH
+                       dvp.dp_timeout = -1;
+#else
+                       if (pollstate == poll_idle)
+                               dvp.dp_timeout = -1;
+                       else
+                               dvp.dp_timeout = ISC_SOCKET_POLLWATCH_TIMEOUT;
+#endif /* ISC_SOCKET_USE_POLLWATCH */
+                       cc = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
+#elif defined(USE_SELECT)
+                       LOCK(&manager->lock);
+                       memcpy(manager->read_fds_copy, manager->read_fds,
+                              manager->fd_bufsize);
+                       memcpy(manager->write_fds_copy, manager->write_fds,
+                              manager->fd_bufsize);
+                       maxfd = manager->maxfd + 1;
+                       UNLOCK(&manager->lock);
+
+                       cc = select(maxfd, manager->read_fds_copy,
+                                   manager->write_fds_copy, NULL, NULL);
+#endif /* USE_KQUEUE */
+
+                       if (cc < 0 && !SOFT_ERROR(errno)) {
+                               isc__strerror(errno, strbuf, sizeof(strbuf));
+                               FATAL_ERROR(__FILE__, __LINE__,
+                                           "%s %s: %s", fnname,
+                                           isc_msgcat_get(isc_msgcat,
+                                                          ISC_MSGSET_GENERAL,
+                                                          ISC_MSG_FAILED,
+                                                          "failed"), strbuf);
+                       }
+
+#if defined(USE_DEVPOLL) && defined(ISC_SOCKET_USE_POLLWATCH)
+                       if (cc == 0) {
+                               if (pollstate == poll_active)
+                                       pollstate = poll_checking;
+                               else if (pollstate == poll_checking)
+                                       pollstate = poll_idle;
+                       } else if (cc > 0) {
+                               if (pollstate == poll_checking) {
+                                       /*
+                                        * XXX: We'd like to use a more
+                                        * verbose log level as it's actually an
+                                        * unexpected event, but the kernel bug
+                                        * reportedly happens pretty frequently
+                                        * (and it can also be a false positive)
+                                        * so it would be just too noisy.
+                                        */
+                                       manager_log(manager,
+                                                   ISC_LOGCATEGORY_GENERAL,
+                                                   ISC_LOGMODULE_SOCKET,
+                                                   ISC_LOG_DEBUG(1),
+                                                   "unexpected POLL timeout");
+                               }
+                               pollstate = poll_active;
+                       }
+#endif
+               } while (cc < 0);
+
+#if defined(USE_KQUEUE) || defined (USE_EPOLL) || defined (USE_DEVPOLL)
+               done = process_fds(manager, manager->events, cc);
+#elif defined(USE_SELECT)
+               process_fds(manager, maxfd, manager->read_fds_copy,
+                           manager->write_fds_copy);
+
+               /*
+                * Process reads on internal, control fd.
+                */
+               if (FD_ISSET(ctlfd, manager->read_fds_copy))
+                       done = process_ctlfd(manager);
+#endif
+       }
+
+       manager_log(manager, TRACE, "%s",
+                   isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                  ISC_MSG_EXITING, "watcher exiting"));
+
+       return ((isc_threadresult_t)0);
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+void
+isc__socketmgr_setreserved(isc_socketmgr_t *manager, isc_uint32_t reserved) {
+
+       REQUIRE(VALID_MANAGER(manager));
+
+       manager->reserved = reserved;
+}
+
+/*
+ * Create a new socket manager.
+ */
+
+static isc_result_t
+setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) {
+       isc_result_t result;
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+       char strbuf[ISC_STRERRORSIZE];
+#endif
+
+#ifdef USE_KQUEUE
+       manager->nevents = ISC_SOCKET_MAXEVENTS;
+       manager->events = isc_mem_get(mctx, sizeof(struct kevent) *
+                                     manager->nevents);
+       if (manager->events == NULL)
+               return (ISC_R_NOMEMORY);
+       manager->kqueue_fd = kqueue();
+       if (manager->kqueue_fd == -1) {
+               result = isc__errno2result(errno);
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "kqueue %s: %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"),
+                                strbuf);
+               isc_mem_put(mctx, manager->events,
+                           sizeof(struct kevent) * manager->nevents);
+               return (result);
+       }
+
+#ifdef ISC_PLATFORM_USETHREADS
+       result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+       if (result != ISC_R_SUCCESS) {
+               close(manager->kqueue_fd);
+               isc_mem_put(mctx, manager->events,
+                           sizeof(struct kevent) * manager->nevents);
+               return (result);
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+#elif defined(USE_EPOLL)
+       manager->nevents = ISC_SOCKET_MAXEVENTS;
+       manager->events = isc_mem_get(mctx, sizeof(struct epoll_event) *
+                                     manager->nevents);
+       if (manager->events == NULL)
+               return (ISC_R_NOMEMORY);
+       manager->epoll_fd = epoll_create(manager->nevents);
+       if (manager->epoll_fd == -1) {
+               result = isc__errno2result(errno);
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "epoll_create %s: %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"),
+                                strbuf);
+               isc_mem_put(mctx, manager->events,
+                           sizeof(struct epoll_event) * manager->nevents);
+               return (result);
+       }
+#ifdef ISC_PLATFORM_USETHREADS
+       result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+       if (result != ISC_R_SUCCESS) {
+               close(manager->epoll_fd);
+               isc_mem_put(mctx, manager->events,
+                           sizeof(struct epoll_event) * manager->nevents);
+               return (result);
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+#elif defined(USE_DEVPOLL)
+       /*
+        * XXXJT: /dev/poll seems to reject large numbers of events,
+        * so we should be careful about redefining ISC_SOCKET_MAXEVENTS.
+        */
+       manager->nevents = ISC_SOCKET_MAXEVENTS;
+       manager->events = isc_mem_get(mctx, sizeof(struct pollfd) *
+                                     manager->nevents);
+       if (manager->events == NULL)
+               return (ISC_R_NOMEMORY);
+       /*
+        * Note: fdpollinfo should be able to support all possible FDs, so
+        * it must have maxsocks entries (not nevents).
+        */
+       manager->fdpollinfo = isc_mem_get(mctx, sizeof(pollinfo_t) *
+                                         manager->maxsocks);
+       if (manager->fdpollinfo == NULL) {
+               isc_mem_put(mctx, manager->events,
+                           sizeof(pollinfo_t) * manager->maxsocks);
+               return (ISC_R_NOMEMORY);
+       }
+       memset(manager->fdpollinfo, 0, sizeof(pollinfo_t) * manager->maxsocks);
+       manager->devpoll_fd = open("/dev/poll", O_RDWR);
+       if (manager->devpoll_fd == -1) {
+               result = isc__errno2result(errno);
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "open(/dev/poll) %s: %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"),
+                                strbuf);
+               isc_mem_put(mctx, manager->events,
+                           sizeof(struct pollfd) * manager->nevents);
+               isc_mem_put(mctx, manager->fdpollinfo,
+                           sizeof(pollinfo_t) * manager->maxsocks);
+               return (result);
+       }
+#ifdef ISC_PLATFORM_USETHREADS
+       result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+       if (result != ISC_R_SUCCESS) {
+               close(manager->devpoll_fd);
+               isc_mem_put(mctx, manager->events,
+                           sizeof(struct pollfd) * manager->nevents);
+               isc_mem_put(mctx, manager->fdpollinfo,
+                           sizeof(pollinfo_t) * manager->maxsocks);
+               return (result);
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+#elif defined(USE_SELECT)
+       UNUSED(result);
+
+#if ISC_SOCKET_MAXSOCKETS > FD_SETSIZE
+       /*
+        * Note: this code should also cover the case of MAXSOCKETS <=
+        * FD_SETSIZE, but we separate the cases to avoid possible portability
+        * issues regarding howmany() and the actual representation of fd_set.
+        */
+       manager->fd_bufsize = howmany(manager->maxsocks, NFDBITS) *
+               sizeof(fd_mask);
+#else
+       manager->fd_bufsize = sizeof(fd_set);
+#endif
+
+       manager->read_fds = NULL;
+       manager->read_fds_copy = NULL;
+       manager->write_fds = NULL;
+       manager->write_fds_copy = NULL;
+
+       manager->read_fds = isc_mem_get(mctx, manager->fd_bufsize);
+       if (manager->read_fds != NULL)
+               manager->read_fds_copy = isc_mem_get(mctx, manager->fd_bufsize);
+       if (manager->read_fds_copy != NULL)
+               manager->write_fds = isc_mem_get(mctx, manager->fd_bufsize);
+       if (manager->write_fds != NULL) {
+               manager->write_fds_copy = isc_mem_get(mctx,
+                                                     manager->fd_bufsize);
+       }
+       if (manager->write_fds_copy == NULL) {
+               if (manager->write_fds != NULL) {
+                       isc_mem_put(mctx, manager->write_fds,
+                                   manager->fd_bufsize);
+               }
+               if (manager->read_fds_copy != NULL) {
+                       isc_mem_put(mctx, manager->read_fds_copy,
+                                   manager->fd_bufsize);
+               }
+               if (manager->read_fds != NULL) {
+                       isc_mem_put(mctx, manager->read_fds,
+                                   manager->fd_bufsize);
+               }
+               return (ISC_R_NOMEMORY);
+       }
+       memset(manager->read_fds, 0, manager->fd_bufsize);
+       memset(manager->write_fds, 0, manager->fd_bufsize);
+
+#ifdef ISC_PLATFORM_USETHREADS
+       (void)watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+       manager->maxfd = manager->pipe_fds[0];
+#else /* ISC_PLATFORM_USETHREADS */
+       manager->maxfd = 0;
+#endif /* ISC_PLATFORM_USETHREADS */
+#endif /* USE_KQUEUE */
+
+       return (ISC_R_SUCCESS);
+}
+
+static void
+cleanup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) {
+#ifdef ISC_PLATFORM_USETHREADS
+       isc_result_t result;
+
+       result = unwatch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
+       if (result != ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "epoll_ctl(DEL) %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifdef USE_KQUEUE
+       close(manager->kqueue_fd);
+       isc_mem_put(mctx, manager->events,
+                   sizeof(struct kevent) * manager->nevents);
+#elif defined(USE_EPOLL)
+       close(manager->epoll_fd);
+       isc_mem_put(mctx, manager->events,
+                   sizeof(struct epoll_event) * manager->nevents);
+#elif defined(USE_DEVPOLL)
+       close(manager->devpoll_fd);
+       isc_mem_put(mctx, manager->events,
+                   sizeof(struct pollfd) * manager->nevents);
+       isc_mem_put(mctx, manager->fdpollinfo,
+                   sizeof(pollinfo_t) * manager->maxsocks);
+#elif defined(USE_SELECT)
+       if (manager->read_fds != NULL)
+               isc_mem_put(mctx, manager->read_fds, manager->fd_bufsize);
+       if (manager->read_fds_copy != NULL)
+               isc_mem_put(mctx, manager->read_fds_copy, manager->fd_bufsize);
+       if (manager->write_fds != NULL)
+               isc_mem_put(mctx, manager->write_fds, manager->fd_bufsize);
+       if (manager->write_fds_copy != NULL)
+               isc_mem_put(mctx, manager->write_fds_copy, manager->fd_bufsize);
+#endif /* USE_KQUEUE */
+}
+
+isc_result_t
+isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
+       return (isc_socketmgr_create2(mctx, managerp, 0));
+}
+
+isc_result_t
+isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
+                     unsigned int maxsocks)
+{
+       int i;
+       isc_socketmgr_t *manager;
+#ifdef ISC_PLATFORM_USETHREADS
+       char strbuf[ISC_STRERRORSIZE];
+#endif
+       isc_result_t result;
+
+       REQUIRE(managerp != NULL && *managerp == NULL);
+
+#ifndef ISC_PLATFORM_USETHREADS
+       if (socketmgr != NULL) {
+               /* Don't allow maxsocks to be updated */
+               if (maxsocks > 0 && socketmgr->maxsocks != maxsocks)
+                       return (ISC_R_EXISTS);
+
+               socketmgr->refs++;
+               *managerp = socketmgr;
+               return (ISC_R_SUCCESS);
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       if (maxsocks == 0)
+               maxsocks = ISC_SOCKET_MAXSOCKETS;
+
+       manager = isc_mem_get(mctx, sizeof(*manager));
+       if (manager == NULL)
+               return (ISC_R_NOMEMORY);
+
+       /* zero-clear so that necessary cleanup on failure will be easy */
+       memset(manager, 0, sizeof(*manager));
+       manager->maxsocks = maxsocks;
+       manager->reserved = 0;
+       manager->fds = isc_mem_get(mctx,
+                                  manager->maxsocks * sizeof(isc_socket_t *));
+       if (manager->fds == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto free_manager;
+       }
+       manager->fdstate = isc_mem_get(mctx, manager->maxsocks * sizeof(int));
+       if (manager->fdstate == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto free_manager;
+       }
+       manager->stats = NULL;
+
+       manager->magic = SOCKET_MANAGER_MAGIC;
+       manager->mctx = NULL;
+       memset(manager->fds, 0, manager->maxsocks * sizeof(isc_socket_t *));
+       ISC_LIST_INIT(manager->socklist);
+       result = isc_mutex_init(&manager->lock);
+       if (result != ISC_R_SUCCESS)
+               goto free_manager;
+       manager->fdlock = isc_mem_get(mctx, FDLOCK_COUNT * sizeof(isc_mutex_t));
+       if (manager->fdlock == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto cleanup_lock;
+       }
+       for (i = 0; i < FDLOCK_COUNT; i++) {
+               result = isc_mutex_init(&manager->fdlock[i]);
+               if (result != ISC_R_SUCCESS) {
+                       while (--i >= 0)
+                               DESTROYLOCK(&manager->fdlock[i]);
+                       isc_mem_put(mctx, manager->fdlock,
+                                   FDLOCK_COUNT * sizeof(isc_mutex_t));
+                       manager->fdlock = NULL;
+                       goto cleanup_lock;
+               }
+       }
+
+#ifdef ISC_PLATFORM_USETHREADS
+       if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_condition_init() %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               result = ISC_R_UNEXPECTED;
+               goto cleanup_lock;
+       }
+
+       /*
+        * Create the special fds that will be used to wake up the
+        * select/poll loop when something internal needs to be done.
+        */
+       if (pipe(manager->pipe_fds) != 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "pipe() %s: %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"),
+                                strbuf);
+               result = ISC_R_UNEXPECTED;
+               goto cleanup_condition;
+       }
+
+       RUNTIME_CHECK(make_nonblock(manager->pipe_fds[0]) == ISC_R_SUCCESS);
+#if 0
+       RUNTIME_CHECK(make_nonblock(manager->pipe_fds[1]) == ISC_R_SUCCESS);
+#endif
+#else /* ISC_PLATFORM_USETHREADS */
+       manager->refs = 1;
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       /*
+        * Set up initial state for the select loop
+        */
+       result = setup_watcher(mctx, manager);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+       memset(manager->fdstate, 0, manager->maxsocks * sizeof(int));
+#ifdef ISC_PLATFORM_USETHREADS
+       /*
+        * Start up the select/poll thread.
+        */
+       if (isc_thread_create(watcher, manager, &manager->watcher) !=
+           ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_thread_create() %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               cleanup_watcher(mctx, manager);
+               result = ISC_R_UNEXPECTED;
+               goto cleanup;
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+       isc_mem_attach(mctx, &manager->mctx);
+
+#ifndef ISC_PLATFORM_USETHREADS
+       socketmgr = manager;
+#endif /* ISC_PLATFORM_USETHREADS */
+       *managerp = manager;
+
+       return (ISC_R_SUCCESS);
+
+cleanup:
+#ifdef ISC_PLATFORM_USETHREADS
+       (void)close(manager->pipe_fds[0]);
+       (void)close(manager->pipe_fds[1]);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+#ifdef ISC_PLATFORM_USETHREADS
+cleanup_condition:
+       (void)isc_condition_destroy(&manager->shutdown_ok);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+
+cleanup_lock:
+       if (manager->fdlock != NULL) {
+               for (i = 0; i < FDLOCK_COUNT; i++)
+                       DESTROYLOCK(&manager->fdlock[i]);
+       }
+       DESTROYLOCK(&manager->lock);
+
+free_manager:
+       if (manager->fdlock != NULL) {
+               isc_mem_put(mctx, manager->fdlock,
+                           FDLOCK_COUNT * sizeof(isc_mutex_t));
+       }
+       if (manager->fdstate != NULL) {
+               isc_mem_put(mctx, manager->fdstate,
+                           manager->maxsocks * sizeof(int));
+       }
+       if (manager->fds != NULL) {
+               isc_mem_put(mctx, manager->fds,
+                           manager->maxsocks * sizeof(isc_socket_t *));
+       }
+       isc_mem_put(mctx, manager, sizeof(*manager));
+
+       return (result);
+}
+
+isc_result_t
+isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) {
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(nsockp != NULL);
+
+       *nsockp = manager->maxsocks;
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) {
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(ISC_LIST_EMPTY(manager->socklist));
+       REQUIRE(manager->stats == NULL);
+       REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max);
+
+       isc_stats_attach(stats, &manager->stats);
+}
+
+void
+isc_socketmgr_destroy(isc_socketmgr_t **managerp) {
+       isc_socketmgr_t *manager;
+       int i;
+       isc_mem_t *mctx;
+
+       /*
+        * Destroy a socket manager.
+        */
+
+       REQUIRE(managerp != NULL);
+       manager = *managerp;
+       REQUIRE(VALID_MANAGER(manager));
+
+#ifndef ISC_PLATFORM_USETHREADS
+       if (manager->refs > 1) {
+               manager->refs--;
+               *managerp = NULL;
+               return;
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       LOCK(&manager->lock);
+
+#ifdef ISC_PLATFORM_USETHREADS
+       /*
+        * Wait for all sockets to be destroyed.
+        */
+       while (!ISC_LIST_EMPTY(manager->socklist)) {
+               manager_log(manager, CREATION, "%s",
+                           isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                                          ISC_MSG_SOCKETSREMAIN,
+                                          "sockets exist"));
+               WAIT(&manager->shutdown_ok, &manager->lock);
+       }
+#else /* ISC_PLATFORM_USETHREADS */
+       /*
+        * Hope all sockets have been destroyed.
+        */
+       if (!ISC_LIST_EMPTY(manager->socklist)) {
+               manager_log(manager, CREATION, "%s",
+                           isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                                          ISC_MSG_SOCKETSREMAIN,
+                                          "sockets exist"));
+               INSIST(0);
+       }
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       UNLOCK(&manager->lock);
+
+       /*
+        * Here, poke our select/poll thread.  Do this by closing the write
+        * half of the pipe, which will send EOF to the read half.
+        * This is currently a no-op in the non-threaded case.
+        */
+       select_poke(manager, 0, SELECT_POKE_SHUTDOWN);
+
+#ifdef ISC_PLATFORM_USETHREADS
+       /*
+        * Wait for thread to exit.
+        */
+       if (isc_thread_join(manager->watcher, NULL) != ISC_R_SUCCESS)
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_thread_join() %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       /*
+        * Clean up.
+        */
+       cleanup_watcher(manager->mctx, manager);
+
+#ifdef ISC_PLATFORM_USETHREADS
+       (void)close(manager->pipe_fds[0]);
+       (void)close(manager->pipe_fds[1]);
+       (void)isc_condition_destroy(&manager->shutdown_ok);
+#endif /* ISC_PLATFORM_USETHREADS */
+
+       for (i = 0; i < (int)manager->maxsocks; i++)
+               if (manager->fdstate[i] == CLOSE_PENDING) /* no need to lock */
+                       (void)close(i);
+
+       isc_mem_put(manager->mctx, manager->fds,
+                   manager->maxsocks * sizeof(isc_socket_t *));
+       isc_mem_put(manager->mctx, manager->fdstate,
+                   manager->maxsocks * sizeof(int));
+
+       if (manager->stats != NULL)
+               isc_stats_detach(&manager->stats);
+
+       if (manager->fdlock != NULL) {
+               for (i = 0; i < FDLOCK_COUNT; i++)
+                       DESTROYLOCK(&manager->fdlock[i]);
+               isc_mem_put(manager->mctx, manager->fdlock,
+                           FDLOCK_COUNT * sizeof(isc_mutex_t));
+       }
+       DESTROYLOCK(&manager->lock);
+       manager->magic = 0;
+       mctx= manager->mctx;
+       isc_mem_put(mctx, manager, sizeof(*manager));
+
+       isc_mem_detach(&mctx);
+
+       *managerp = NULL;
+}
+
+static isc_result_t
+socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+           unsigned int flags)
+{
+       int io_state;
+       isc_boolean_t have_lock = ISC_FALSE;
+       isc_task_t *ntask = NULL;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       dev->ev_sender = task;
+
+       if (sock->type == isc_sockettype_udp) {
+               io_state = doio_recv(sock, dev);
+       } else {
+               LOCK(&sock->lock);
+               have_lock = ISC_TRUE;
+
+               if (ISC_LIST_EMPTY(sock->recv_list))
+                       io_state = doio_recv(sock, dev);
+               else
+                       io_state = DOIO_SOFT;
+       }
+
+       switch (io_state) {
+       case DOIO_SOFT:
+               /*
+                * We couldn't read all or part of the request right now, so
+                * queue it.
+                *
+                * Attach to socket and to task
+                */
+               isc_task_attach(task, &ntask);
+               dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+               if (!have_lock) {
+                       LOCK(&sock->lock);
+                       have_lock = ISC_TRUE;
+               }
+
+               /*
+                * Enqueue the request.  If the socket was previously not being
+                * watched, poke the watcher to start paying attention to it.
+                */
+               if (ISC_LIST_EMPTY(sock->recv_list) && !sock->pending_recv)
+                       select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
+               ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
+
+               socket_log(sock, NULL, EVENT, NULL, 0, 0,
+                          "socket_recv: event %p -> task %p",
+                          dev, ntask);
+
+               if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+                       result = ISC_R_INPROGRESS;
+               break;
+
+       case DOIO_EOF:
+               dev->result = ISC_R_EOF;
+               /* fallthrough */
+
+       case DOIO_HARD:
+       case DOIO_SUCCESS:
+               if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
+                       send_recvdone_event(sock, &dev);
+               break;
+       }
+
+       if (have_lock)
+               UNLOCK(&sock->lock);
+
+       return (result);
+}
+
+isc_result_t
+isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+                unsigned int minimum, isc_task_t *task,
+                isc_taskaction_t action, const void *arg)
+{
+       isc_socketevent_t *dev;
+       isc_socketmgr_t *manager;
+       unsigned int iocount;
+       isc_buffer_t *buffer;
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(buflist != NULL);
+       REQUIRE(!ISC_LIST_EMPTY(*buflist));
+       REQUIRE(task != NULL);
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       iocount = isc_bufferlist_availablecount(buflist);
+       REQUIRE(iocount > 0);
+
+       INSIST(sock->bound);
+
+       dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
+       if (dev == NULL) {
+               return (ISC_R_NOMEMORY);
+       }
+
+       /*
+        * UDP sockets are always partial read
+        */
+       if (sock->type == isc_sockettype_udp)
+               dev->minimum = 1;
+       else {
+               if (minimum == 0)
+                       dev->minimum = iocount;
+               else
+                       dev->minimum = minimum;
+       }
+
+       /*
+        * Move each buffer from the passed in list to our internal one.
+        */
+       buffer = ISC_LIST_HEAD(*buflist);
+       while (buffer != NULL) {
+               ISC_LIST_DEQUEUE(*buflist, buffer, link);
+               ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+               buffer = ISC_LIST_HEAD(*buflist);
+       }
+
+       return (socket_recv(sock, dev, task, 0));
+}
+
+isc_result_t
+isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
+               isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       isc_socketevent_t *dev;
+       isc_socketmgr_t *manager;
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       INSIST(sock->bound);
+
+       dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
+       if (dev == NULL)
+               return (ISC_R_NOMEMORY);
+
+       return (isc_socket_recv2(sock, region, minimum, task, dev, 0));
+}
+
+isc_result_t
+isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
+                unsigned int minimum, isc_task_t *task,
+                isc_socketevent_t *event, unsigned int flags)
+{
+       event->ev_sender = sock;
+       event->result = ISC_R_UNEXPECTED;
+       ISC_LIST_INIT(event->bufferlist);
+       event->region = *region;
+       event->n = 0;
+       event->offset = 0;
+       event->attributes = 0;
+
+       /*
+        * UDP sockets are always partial read.
+        */
+       if (sock->type == isc_sockettype_udp)
+               event->minimum = 1;
+       else {
+               if (minimum == 0)
+                       event->minimum = region->length;
+               else
+                       event->minimum = minimum;
+       }
+
+       return (socket_recv(sock, event, task, flags));
+}
+
+static isc_result_t
+socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+           isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+           unsigned int flags)
+{
+       int io_state;
+       isc_boolean_t have_lock = ISC_FALSE;
+       isc_task_t *ntask = NULL;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       dev->ev_sender = task;
+
+       set_dev_address(address, sock, dev);
+       if (pktinfo != NULL) {
+               dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
+               dev->pktinfo = *pktinfo;
+
+               if (!isc_sockaddr_issitelocal(&dev->address) &&
+                   !isc_sockaddr_islinklocal(&dev->address)) {
+                       socket_log(sock, NULL, TRACE, isc_msgcat,
+                                  ISC_MSGSET_SOCKET, ISC_MSG_PKTINFOPROVIDED,
+                                  "pktinfo structure provided, ifindex %u "
+                                  "(set to 0)", pktinfo->ipi6_ifindex);
+
+                       /*
+                        * Set the pktinfo index to 0 here, to let the
+                        * kernel decide what interface it should send on.
+                        */
+                       dev->pktinfo.ipi6_ifindex = 0;
+               }
+       }
+
+       if (sock->type == isc_sockettype_udp)
+               io_state = doio_send(sock, dev);
+       else {
+               LOCK(&sock->lock);
+               have_lock = ISC_TRUE;
+
+               if (ISC_LIST_EMPTY(sock->send_list))
+                       io_state = doio_send(sock, dev);
+               else
+                       io_state = DOIO_SOFT;
+       }
+
+       switch (io_state) {
+       case DOIO_SOFT:
+               /*
+                * We couldn't send all or part of the request right now, so
+                * queue it unless ISC_SOCKFLAG_NORETRY is set.
+                */
+               if ((flags & ISC_SOCKFLAG_NORETRY) == 0) {
+                       isc_task_attach(task, &ntask);
+                       dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+                       if (!have_lock) {
+                               LOCK(&sock->lock);
+                               have_lock = ISC_TRUE;
+                       }
+
+                       /*
+                        * Enqueue the request.  If the socket was previously
+                        * not being watched, poke the watcher to start
+                        * paying attention to it.
+                        */
+                       if (ISC_LIST_EMPTY(sock->send_list) &&
+                           !sock->pending_send)
+                               select_poke(sock->manager, sock->fd,
+                                           SELECT_POKE_WRITE);
+                       ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
+
+                       socket_log(sock, NULL, EVENT, NULL, 0, 0,
+                                  "socket_send: event %p -> task %p",
+                                  dev, ntask);
+
+                       if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+                               result = ISC_R_INPROGRESS;
+                       break;
+               }
+
+       case DOIO_HARD:
+       case DOIO_SUCCESS:
+               if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
+                       send_senddone_event(sock, &dev);
+               break;
+       }
+
+       if (have_lock)
+               UNLOCK(&sock->lock);
+
+       return (result);
+}
+
+isc_result_t
+isc_socket_send(isc_socket_t *sock, isc_region_t *region,
+               isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       /*
+        * REQUIRE() checking is performed in isc_socket_sendto().
+        */
+       return (isc_socket_sendto(sock, region, task, action, arg, NULL,
+                                 NULL));
+}
+
+isc_result_t
+isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
+                 isc_task_t *task, isc_taskaction_t action, const void *arg,
+                 isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+       isc_socketevent_t *dev;
+       isc_socketmgr_t *manager;
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(region != NULL);
+       REQUIRE(task != NULL);
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       INSIST(sock->bound);
+
+       dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
+       if (dev == NULL) {
+               return (ISC_R_NOMEMORY);
+       }
+
+       dev->region = *region;
+
+       return (socket_send(sock, dev, task, address, pktinfo, 0));
+}
+
+isc_result_t
+isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+                isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       return (isc_socket_sendtov(sock, buflist, task, action, arg, NULL,
+                                  NULL));
+}
+
+isc_result_t
+isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+                  isc_task_t *task, isc_taskaction_t action, const void *arg,
+                  isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+       isc_socketevent_t *dev;
+       isc_socketmgr_t *manager;
+       unsigned int iocount;
+       isc_buffer_t *buffer;
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(buflist != NULL);
+       REQUIRE(!ISC_LIST_EMPTY(*buflist));
+       REQUIRE(task != NULL);
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       iocount = isc_bufferlist_usedcount(buflist);
+       REQUIRE(iocount > 0);
+
+       dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
+       if (dev == NULL) {
+               return (ISC_R_NOMEMORY);
+       }
+
+       /*
+        * Move each buffer from the passed in list to our internal one.
+        */
+       buffer = ISC_LIST_HEAD(*buflist);
+       while (buffer != NULL) {
+               ISC_LIST_DEQUEUE(*buflist, buffer, link);
+               ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+               buffer = ISC_LIST_HEAD(*buflist);
+       }
+
+       return (socket_send(sock, dev, task, address, pktinfo, 0));
+}
+
+isc_result_t
+isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+                  isc_task_t *task,
+                  isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+                  isc_socketevent_t *event, unsigned int flags)
+{
+       REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0);
+       if ((flags & ISC_SOCKFLAG_NORETRY) != 0)
+               REQUIRE(sock->type == isc_sockettype_udp);
+       event->ev_sender = sock;
+       event->result = ISC_R_UNEXPECTED;
+       ISC_LIST_INIT(event->bufferlist);
+       event->region = *region;
+       event->n = 0;
+       event->offset = 0;
+       event->attributes = 0;
+
+       return (socket_send(sock, event, task, address, pktinfo, flags));
+}
+
+void
+isc_socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active) {
+#ifdef ISC_PLATFORM_HAVESYSUNH
+       int s;
+       struct stat sb;
+       char strbuf[ISC_STRERRORSIZE];
+
+       if (sockaddr->type.sa.sa_family != AF_UNIX)
+               return;
+
+#ifndef S_ISSOCK
+#if defined(S_IFMT) && defined(S_IFSOCK)
+#define S_ISSOCK(mode) ((mode & S_IFMT)==S_IFSOCK)
+#elif defined(_S_IFMT) && defined(S_IFSOCK)
+#define S_ISSOCK(mode) ((mode & _S_IFMT)==S_IFSOCK)
+#endif
+#endif
+
+#ifndef S_ISFIFO
+#if defined(S_IFMT) && defined(S_IFIFO)
+#define S_ISFIFO(mode) ((mode & S_IFMT)==S_IFIFO)
+#elif defined(_S_IFMT) && defined(S_IFIFO)
+#define S_ISFIFO(mode) ((mode & _S_IFMT)==S_IFIFO)
+#endif
+#endif
+
+#if !defined(S_ISFIFO) && !defined(S_ISSOCK)
+#error You need to define S_ISFIFO and S_ISSOCK as appropriate for your platform.  See <sys/stat.h>.
+#endif
+
+#ifndef S_ISFIFO
+#define S_ISFIFO(mode) 0
+#endif
+
+#ifndef S_ISSOCK
+#define S_ISSOCK(mode) 0
+#endif
+
+       if (active) {
+               if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) {
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                                     "isc_socket_cleanunix: stat(%s): %s",
+                                     sockaddr->type.sunix.sun_path, strbuf);
+                       return;
+               }
+               if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                                     "isc_socket_cleanunix: %s: not a socket",
+                                     sockaddr->type.sunix.sun_path);
+                       return;
+               }
+               if (unlink(sockaddr->type.sunix.sun_path) < 0) {
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                                     "isc_socket_cleanunix: unlink(%s): %s",
+                                     sockaddr->type.sunix.sun_path, strbuf);
+               }
+               return;
+       }
+
+       s = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (s < 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                             ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+                             "isc_socket_cleanunix: socket(%s): %s",
+                             sockaddr->type.sunix.sun_path, strbuf);
+               return;
+       }
+
+       if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) {
+               switch (errno) {
+               case ENOENT:    /* We exited cleanly last time */
+                       break;
+               default:
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+                                     "isc_socket_cleanunix: stat(%s): %s",
+                                     sockaddr->type.sunix.sun_path, strbuf);
+                       break;
+               }
+               goto cleanup;
+       }
+
+       if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
+               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                             ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+                             "isc_socket_cleanunix: %s: not a socket",
+                             sockaddr->type.sunix.sun_path);
+               goto cleanup;
+       }
+
+       if (connect(s, (struct sockaddr *)&sockaddr->type.sunix,
+                   sizeof(sockaddr->type.sunix)) < 0) {
+               switch (errno) {
+               case ECONNREFUSED:
+               case ECONNRESET:
+                       if (unlink(sockaddr->type.sunix.sun_path) < 0) {
+                               isc__strerror(errno, strbuf, sizeof(strbuf));
+                               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                             ISC_LOGMODULE_SOCKET,
+                                             ISC_LOG_WARNING,
+                                             "isc_socket_cleanunix: "
+                                             "unlink(%s): %s",
+                                             sockaddr->type.sunix.sun_path,
+                                             strbuf);
+                       }
+                       break;
+               default:
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                                     ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
+                                     "isc_socket_cleanunix: connect(%s): %s",
+                                     sockaddr->type.sunix.sun_path, strbuf);
+                       break;
+               }
+       }
+ cleanup:
+       close(s);
+#else
+       UNUSED(sockaddr);
+       UNUSED(active);
+#endif
+}
+
+isc_result_t
+isc_socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm,
+                   isc_uint32_t owner, isc_uint32_t group)
+{
+#ifdef ISC_PLATFORM_HAVESYSUNH
+       isc_result_t result = ISC_R_SUCCESS;
+       char strbuf[ISC_STRERRORSIZE];
+       char path[sizeof(sockaddr->type.sunix.sun_path)];
+#ifdef NEED_SECURE_DIRECTORY
+       char *slash;
+#endif
+
+       REQUIRE(sockaddr->type.sa.sa_family == AF_UNIX);
+       INSIST(strlen(sockaddr->type.sunix.sun_path) < sizeof(path));
+       strcpy(path, sockaddr->type.sunix.sun_path);
+
+#ifdef NEED_SECURE_DIRECTORY
+       slash = strrchr(path, '/');
+       if (slash != NULL) {
+               if (slash != path)
+                       *slash = '\0';
+               else
+                       strcpy(path, "/");
+       } else
+               strcpy(path, ".");
+#endif
+
+       if (chmod(path, perm) < 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                             ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                             "isc_socket_permunix: chmod(%s, %d): %s",
+                             path, perm, strbuf);
+               result = ISC_R_FAILURE;
+       }
+       if (chown(path, owner, group) < 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+                             ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                             "isc_socket_permunix: chown(%s, %d, %d): %s",
+                             path, owner, group,
+                             strbuf);
+               result = ISC_R_FAILURE;
+       }
+       return (result);
+#else
+       UNUSED(sockaddr);
+       UNUSED(perm);
+       UNUSED(owner);
+       UNUSED(group);
+       return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+isc_result_t
+isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr,
+               unsigned int options) {
+       char strbuf[ISC_STRERRORSIZE];
+       int on = 1;
+
+       LOCK(&sock->lock);
+
+       INSIST(!sock->bound);
+
+       if (sock->pf != sockaddr->type.sa.sa_family) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_FAMILYMISMATCH);
+       }
+       /*
+        * Only set SO_REUSEADDR when we want a specific port.
+        */
+#ifdef AF_UNIX
+       if (sock->pf == AF_UNIX)
+               goto bind_socket;
+#endif
+       if ((options & ISC_SOCKET_REUSEADDRESS) != 0 &&
+           isc_sockaddr_getport(sockaddr) != (in_port_t)0 &&
+           setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
+                      sizeof(on)) < 0) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "setsockopt(%d) %s", sock->fd,
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               /* Press on... */
+       }
+#ifdef AF_UNIX
+ bind_socket:
+#endif
+       if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) {
+               inc_stats(sock->manager->stats,
+                         sock->statsindex[STATID_BINDFAIL]);
+
+               UNLOCK(&sock->lock);
+               switch (errno) {
+               case EACCES:
+                       return (ISC_R_NOPERM);
+               case EADDRNOTAVAIL:
+                       return (ISC_R_ADDRNOTAVAIL);
+               case EADDRINUSE:
+                       return (ISC_R_ADDRINUSE);
+               case EINVAL:
+                       return (ISC_R_BOUND);
+               default:
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
+                                        strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+       }
+
+       socket_log(sock, sockaddr, TRACE,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound");
+       sock->bound = 1;
+
+       UNLOCK(&sock->lock);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_filter(isc_socket_t *sock, const char *filter) {
+#ifdef SO_ACCEPTFILTER
+       char strbuf[ISC_STRERRORSIZE];
+       struct accept_filter_arg afa;
+#else
+       UNUSED(sock);
+       UNUSED(filter);
+#endif
+
+       REQUIRE(VALID_SOCKET(sock));
+
+#ifdef SO_ACCEPTFILTER
+       bzero(&afa, sizeof(afa));
+       strncpy(afa.af_name, filter, sizeof(afa.af_name));
+       if (setsockopt(sock->fd, SOL_SOCKET, SO_ACCEPTFILTER,
+                        &afa, sizeof(afa)) == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+                          ISC_MSG_FILTER, "setsockopt(SO_ACCEPTFILTER): %s",
+                          strbuf);
+               return (ISC_R_FAILURE);
+       }
+       return (ISC_R_SUCCESS);
+#else
+       return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+/*
+ * Set up to listen on a given socket.  We do this by creating an internal
+ * event that will be dispatched when the socket has read activity.  The
+ * watcher will send the internal event to the task when there is a new
+ * connection.
+ *
+ * Unlike in read, we don't preallocate a done event here.  Every time there
+ * is a new connection we'll have to allocate a new one anyway, so we might
+ * as well keep things simple rather than having to track them.
+ */
+isc_result_t
+isc_socket_listen(isc_socket_t *sock, unsigned int backlog) {
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+
+       REQUIRE(!sock->listener);
+       REQUIRE(sock->bound);
+       REQUIRE(sock->type == isc_sockettype_tcp ||
+               sock->type == isc_sockettype_unix);
+
+       if (backlog == 0)
+               backlog = SOMAXCONN;
+
+       if (listen(sock->fd, (int)backlog) < 0) {
+               UNLOCK(&sock->lock);
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+
+               UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf);
+
+               return (ISC_R_UNEXPECTED);
+       }
+
+       sock->listener = 1;
+
+       UNLOCK(&sock->lock);
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * This should try to do aggressive accept() XXXMLG
+ */
+isc_result_t
+isc_socket_accept(isc_socket_t *sock,
+                 isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       isc_socket_newconnev_t *dev;
+       isc_socketmgr_t *manager;
+       isc_task_t *ntask = NULL;
+       isc_socket_t *nsock;
+       isc_result_t result;
+       isc_boolean_t do_poke = ISC_FALSE;
+
+       REQUIRE(VALID_SOCKET(sock));
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       LOCK(&sock->lock);
+
+       REQUIRE(sock->listener);
+
+       /*
+        * Sender field is overloaded here with the task we will be sending
+        * this event to.  Just before the actual event is delivered the
+        * actual ev_sender will be touched up to be the socket.
+        */
+       dev = (isc_socket_newconnev_t *)
+               isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,
+                                  action, arg, sizeof(*dev));
+       if (dev == NULL) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_NOMEMORY);
+       }
+       ISC_LINK_INIT(dev, ev_link);
+
+       result = allocate_socket(manager, sock->type, &nsock);
+       if (result != ISC_R_SUCCESS) {
+               isc_event_free(ISC_EVENT_PTR(&dev));
+               UNLOCK(&sock->lock);
+               return (result);
+       }
+
+       /*
+        * Attach to socket and to task.
+        */
+       isc_task_attach(task, &ntask);
+       nsock->references++;
+       nsock->statsindex = sock->statsindex;
+
+       dev->ev_sender = ntask;
+       dev->newsocket = nsock;
+
+       /*
+        * Poke watcher here.  We still have the socket locked, so there
+        * is no race condition.  We will keep the lock for such a short
+        * bit of time waking it up now or later won't matter all that much.
+        */
+       if (ISC_LIST_EMPTY(sock->accept_list))
+               do_poke = ISC_TRUE;
+
+       ISC_LIST_ENQUEUE(sock->accept_list, dev, ev_link);
+
+       if (do_poke)
+               select_poke(manager, sock->fd, SELECT_POKE_ACCEPT);
+
+       UNLOCK(&sock->lock);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr,
+                  isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       isc_socket_connev_t *dev;
+       isc_task_t *ntask = NULL;
+       isc_socketmgr_t *manager;
+       int cc;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(addr != NULL);
+       REQUIRE(task != NULL);
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(addr != NULL);
+
+       if (isc_sockaddr_ismulticast(addr))
+               return (ISC_R_MULTICAST);
+
+       LOCK(&sock->lock);
+
+       REQUIRE(!sock->connecting);
+
+       dev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
+                                                       ISC_SOCKEVENT_CONNECT,
+                                                       action, arg,
+                                                       sizeof(*dev));
+       if (dev == NULL) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_NOMEMORY);
+       }
+       ISC_LINK_INIT(dev, ev_link);
+
+       /*
+        * Try to do the connect right away, as there can be only one
+        * outstanding, and it might happen to complete.
+        */
+       sock->peer_address = *addr;
+       cc = connect(sock->fd, &addr->type.sa, addr->length);
+       if (cc < 0) {
+               /*
+                * HP-UX "fails" to connect a UDP socket and sets errno to
+                * EINPROGRESS if it's non-blocking.  We'd rather regard this as
+                * a success and let the user detect it if it's really an error
+                * at the time of sending a packet on the socket.
+                */
+               if (sock->type == isc_sockettype_udp && errno == EINPROGRESS) {
+                       cc = 0;
+                       goto success;
+               }
+               if (SOFT_ERROR(errno) || errno == EINPROGRESS)
+                       goto queue;
+
+               switch (errno) {
+#define ERROR_MATCH(a, b) case a: dev->result = b; goto err_exit;
+                       ERROR_MATCH(EACCES, ISC_R_NOPERM);
+                       ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+                       ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+                       ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED);
+                       ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+#ifdef EHOSTDOWN
+                       ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH);
+#endif
+                       ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH);
+                       ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES);
+                       ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
+                       ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
+                       ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET);
+#undef ERROR_MATCH
+               }
+
+               sock->connected = 0;
+
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__, "%d/%s", errno, strbuf);
+
+               UNLOCK(&sock->lock);
+               inc_stats(sock->manager->stats,
+                         sock->statsindex[STATID_CONNECTFAIL]);
+               isc_event_free(ISC_EVENT_PTR(&dev));
+               return (ISC_R_UNEXPECTED);
+
+       err_exit:
+               sock->connected = 0;
+               isc_task_send(task, ISC_EVENT_PTR(&dev));
+
+               UNLOCK(&sock->lock);
+               inc_stats(sock->manager->stats,
+                         sock->statsindex[STATID_CONNECTFAIL]);
+               return (ISC_R_SUCCESS);
+       }
+
+       /*
+        * If connect completed, fire off the done event.
+        */
+ success:
+       if (cc == 0) {
+               sock->connected = 1;
+               sock->bound = 1;
+               dev->result = ISC_R_SUCCESS;
+               isc_task_send(task, ISC_EVENT_PTR(&dev));
+
+               UNLOCK(&sock->lock);
+
+               inc_stats(sock->manager->stats,
+                         sock->statsindex[STATID_CONNECT]);
+
+               return (ISC_R_SUCCESS);
+       }
+
+ queue:
+
+       /*
+        * Attach to task.
+        */
+       isc_task_attach(task, &ntask);
+
+       sock->connecting = 1;
+
+       dev->ev_sender = ntask;
+
+       /*
+        * Poke watcher here.  We still have the socket locked, so there
+        * is no race condition.  We will keep the lock for such a short
+        * bit of time waking it up now or later won't matter all that much.
+        */
+       if (sock->connect_ev == NULL)
+               select_poke(manager, sock->fd, SELECT_POKE_CONNECT);
+
+       sock->connect_ev = dev;
+
+       UNLOCK(&sock->lock);
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * Called when a socket with a pending connect() finishes.
+ */
+static void
+internal_connect(isc_task_t *me, isc_event_t *ev) {
+       isc_socket_t *sock;
+       isc_socket_connev_t *dev;
+       isc_task_t *task;
+       int cc;
+       ISC_SOCKADDR_LEN_T optlen;
+       char strbuf[ISC_STRERRORSIZE];
+       char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+
+       UNUSED(me);
+       INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
+
+       sock = ev->ev_sender;
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+
+       /*
+        * When the internal event was sent the reference count was bumped
+        * to keep the socket around for us.  Decrement the count here.
+        */
+       INSIST(sock->references > 0);
+       sock->references--;
+       if (sock->references == 0) {
+               UNLOCK(&sock->lock);
+               destroy(&sock);
+               return;
+       }
+
+       /*
+        * Has this event been canceled?
+        */
+       dev = sock->connect_ev;
+       if (dev == NULL) {
+               INSIST(!sock->connecting);
+               UNLOCK(&sock->lock);
+               return;
+       }
+
+       INSIST(sock->connecting);
+       sock->connecting = 0;
+
+       /*
+        * Get any possible error status here.
+        */
+       optlen = sizeof(cc);
+       if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR,
+                      (void *)&cc, (void *)&optlen) < 0)
+               cc = errno;
+       else
+               errno = cc;
+
+       if (errno != 0) {
+               /*
+                * If the error is EAGAIN, just re-select on this
+                * fd and pretend nothing strange happened.
+                */
+               if (SOFT_ERROR(errno) || errno == EINPROGRESS) {
+                       sock->connecting = 1;
+                       select_poke(sock->manager, sock->fd,
+                                   SELECT_POKE_CONNECT);
+                       UNLOCK(&sock->lock);
+
+                       return;
+               }
+
+               inc_stats(sock->manager->stats,
+                         sock->statsindex[STATID_CONNECTFAIL]);
+
+               /*
+                * Translate other errors into ISC_R_* flavors.
+                */
+               switch (errno) {
+#define ERROR_MATCH(a, b) case a: dev->result = b; break;
+                       ERROR_MATCH(EACCES, ISC_R_NOPERM);
+                       ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+                       ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+                       ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED);
+                       ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH);
+#ifdef EHOSTDOWN
+                       ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH);
+#endif
+                       ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH);
+                       ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES);
+                       ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
+                       ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
+                       ERROR_MATCH(ETIMEDOUT, ISC_R_TIMEDOUT);
+                       ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET);
+#undef ERROR_MATCH
+               default:
+                       dev->result = ISC_R_UNEXPECTED;
+                       isc_sockaddr_format(&sock->peer_address, peerbuf,
+                                           sizeof(peerbuf));
+                       isc__strerror(errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "internal_connect: connect(%s) %s",
+                                        peerbuf, strbuf);
+               }
+       } else {
+               inc_stats(sock->manager->stats,
+                         sock->statsindex[STATID_CONNECT]);
+               dev->result = ISC_R_SUCCESS;
+               sock->connected = 1;
+               sock->bound = 1;
+       }
+
+       sock->connect_ev = NULL;
+
+       UNLOCK(&sock->lock);
+
+       task = dev->ev_sender;
+       dev->ev_sender = sock;
+       isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev));
+}
+
+isc_result_t
+isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+       isc_result_t result;
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(addressp != NULL);
+
+       LOCK(&sock->lock);
+
+       if (sock->connected) {
+               *addressp = sock->peer_address;
+               result = ISC_R_SUCCESS;
+       } else {
+               result = ISC_R_NOTCONNECTED;
+       }
+
+       UNLOCK(&sock->lock);
+
+       return (result);
+}
+
+isc_result_t
+isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+       ISC_SOCKADDR_LEN_T len;
+       isc_result_t result;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(addressp != NULL);
+
+       LOCK(&sock->lock);
+
+       if (!sock->bound) {
+               result = ISC_R_NOTBOUND;
+               goto out;
+       }
+
+       result = ISC_R_SUCCESS;
+
+       len = sizeof(addressp->type);
+       if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s",
+                                strbuf);
+               result = ISC_R_UNEXPECTED;
+               goto out;
+       }
+       addressp->length = (unsigned int)len;
+
+ out:
+       UNLOCK(&sock->lock);
+
+       return (result);
+}
+
+/*
+ * Run through the list of events on this socket, and cancel the ones
+ * queued for task "task" of type "how".  "how" is a bitmask.
+ */
+void
+isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       /*
+        * Quick exit if there is nothing to do.  Don't even bother locking
+        * in this case.
+        */
+       if (how == 0)
+               return;
+
+       LOCK(&sock->lock);
+
+       /*
+        * All of these do the same thing, more or less.
+        * Each will:
+        *      o If the internal event is marked as "posted" try to
+        *        remove it from the task's queue.  If this fails, mark it
+        *        as canceled instead, and let the task clean it up later.
+        *      o For each I/O request for that task of that type, post
+        *        its done event with status of "ISC_R_CANCELED".
+        *      o Reset any state needed.
+        */
+       if (((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV)
+           && !ISC_LIST_EMPTY(sock->recv_list)) {
+               isc_socketevent_t      *dev;
+               isc_socketevent_t      *next;
+               isc_task_t             *current_task;
+
+               dev = ISC_LIST_HEAD(sock->recv_list);
+
+               while (dev != NULL) {
+                       current_task = dev->ev_sender;
+                       next = ISC_LIST_NEXT(dev, ev_link);
+
+                       if ((task == NULL) || (task == current_task)) {
+                               dev->result = ISC_R_CANCELED;
+                               send_recvdone_event(sock, &dev);
+                       }
+                       dev = next;
+               }
+       }
+
+       if (((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND)
+           && !ISC_LIST_EMPTY(sock->send_list)) {
+               isc_socketevent_t      *dev;
+               isc_socketevent_t      *next;
+               isc_task_t             *current_task;
+
+               dev = ISC_LIST_HEAD(sock->send_list);
+
+               while (dev != NULL) {
+                       current_task = dev->ev_sender;
+                       next = ISC_LIST_NEXT(dev, ev_link);
+
+                       if ((task == NULL) || (task == current_task)) {
+                               dev->result = ISC_R_CANCELED;
+                               send_senddone_event(sock, &dev);
+                       }
+                       dev = next;
+               }
+       }
+
+       if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT)
+           && !ISC_LIST_EMPTY(sock->accept_list)) {
+               isc_socket_newconnev_t *dev;
+               isc_socket_newconnev_t *next;
+               isc_task_t             *current_task;
+
+               dev = ISC_LIST_HEAD(sock->accept_list);
+               while (dev != NULL) {
+                       current_task = dev->ev_sender;
+                       next = ISC_LIST_NEXT(dev, ev_link);
+
+                       if ((task == NULL) || (task == current_task)) {
+
+                               ISC_LIST_UNLINK(sock->accept_list, dev,
+                                               ev_link);
+
+                               dev->newsocket->references--;
+                               free_socket(&dev->newsocket);
+
+                               dev->result = ISC_R_CANCELED;
+                               dev->ev_sender = sock;
+                               isc_task_sendanddetach(&current_task,
+                                                      ISC_EVENT_PTR(&dev));
+                       }
+
+                       dev = next;
+               }
+       }
+
+       /*
+        * Connecting is not a list.
+        */
+       if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT)
+           && sock->connect_ev != NULL) {
+               isc_socket_connev_t    *dev;
+               isc_task_t             *current_task;
+
+               INSIST(sock->connecting);
+               sock->connecting = 0;
+
+               dev = sock->connect_ev;
+               current_task = dev->ev_sender;
+
+               if ((task == NULL) || (task == current_task)) {
+                       sock->connect_ev = NULL;
+
+                       dev->result = ISC_R_CANCELED;
+                       dev->ev_sender = sock;
+                       isc_task_sendanddetach(&current_task,
+                                              ISC_EVENT_PTR(&dev));
+               }
+       }
+
+       UNLOCK(&sock->lock);
+}
+
+isc_sockettype_t
+isc_socket_gettype(isc_socket_t *sock) {
+       REQUIRE(VALID_SOCKET(sock));
+
+       return (sock->type);
+}
+
+isc_boolean_t
+isc_socket_isbound(isc_socket_t *sock) {
+       isc_boolean_t val;
+
+       LOCK(&sock->lock);
+       val = ((sock->bound) ? ISC_TRUE : ISC_FALSE);
+       UNLOCK(&sock->lock);
+
+       return (val);
+}
+
+void
+isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) {
+#if defined(IPV6_V6ONLY)
+       int onoff = yes ? 1 : 0;
+#else
+       UNUSED(yes);
+       UNUSED(sock);
+#endif
+
+       REQUIRE(VALID_SOCKET(sock));
+
+#ifdef IPV6_V6ONLY
+       if (sock->pf == AF_INET6) {
+               if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+                              (void *)&onoff, sizeof(int)) < 0) {
+                       char strbuf[ISC_STRERRORSIZE];
+
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "setsockopt(%d, IPV6_V6ONLY) "
+                                        "%s: %s", sock->fd,
+                                        isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_GENERAL,
+                                                       ISC_MSG_FAILED,
+                                                       "failed"),
+                                        strbuf);
+               }
+       }
+       FIX_IPV6_RECVPKTINFO(sock);     /* AIX */
+#endif
+}
+
+#ifndef ISC_PLATFORM_USETHREADS
+/* In our assumed scenario, we can simply use a single static object. */
+static isc_socketwait_t swait_private;
+
+int
+isc__socketmgr_waitevents(struct timeval *tvp, isc_socketwait_t **swaitp) {
+       int n;
+#ifdef USE_KQUEUE
+       struct timespec ts, *tsp;
+#endif
+#ifdef USE_EPOLL
+       int timeout;
+#endif
+#ifdef USE_DEVPOLL
+       struct dvpoll dvp;
+#endif
+
+       REQUIRE(swaitp != NULL && *swaitp == NULL);
+
+       if (socketmgr == NULL)
+               return (0);
+
+#ifdef USE_KQUEUE
+       if (tvp != NULL) {
+               ts.tv_sec = tvp->tv_sec;
+               ts.tv_nsec = tvp->tv_usec * 1000;
+               tsp = &ts;
+       } else
+               tsp = NULL;
+       swait_private.nevents = kevent(socketmgr->kqueue_fd, NULL, 0,
+                                      socketmgr->events, socketmgr->nevents,
+                                      tsp);
+       n = swait_private.nevents;
+#elif defined(USE_EPOLL)
+       if (tvp != NULL)
+               timeout = tvp->tv_sec * 1000 + (tvp->tv_usec + 999) / 1000;
+       else
+               timeout = -1;
+       swait_private.nevents = epoll_wait(socketmgr->epoll_fd,
+                                          socketmgr->events,
+                                          socketmgr->nevents, timeout);
+       n = swait_private.nevents;
+#elif defined(USE_DEVPOLL)
+       dvp.dp_fds = socketmgr->events;
+       dvp.dp_nfds = socketmgr->nevents;
+       if (tvp != NULL) {
+               dvp.dp_timeout = tvp->tv_sec * 1000 +
+                       (tvp->tv_usec + 999) / 1000;
+       } else
+               dvp.dp_timeout = -1;
+       swait_private.nevents = ioctl(socketmgr->devpoll_fd, DP_POLL, &dvp);
+       n = swait_private.nevents;
+#elif defined(USE_SELECT)
+       memcpy(socketmgr->read_fds_copy, socketmgr->read_fds,
+              socketmgr->fd_bufsize);
+       memcpy(socketmgr->write_fds_copy, socketmgr->write_fds,
+              socketmgr->fd_bufsize);
+
+       swait_private.readset = socketmgr->read_fds_copy;
+       swait_private.writeset = socketmgr->write_fds_copy;
+       swait_private.maxfd = socketmgr->maxfd + 1;
+
+       n = select(swait_private.maxfd, swait_private.readset,
+                  swait_private.writeset, NULL, tvp);
+#endif
+
+       *swaitp = &swait_private;
+       return (n);
+}
+
+isc_result_t
+isc__socketmgr_dispatch(isc_socketwait_t *swait) {
+       REQUIRE(swait == &swait_private);
+
+       if (socketmgr == NULL)
+               return (ISC_R_NOTFOUND);
+
+#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
+       (void)process_fds(socketmgr, socketmgr->events, swait->nevents);
+       return (ISC_R_SUCCESS);
+#elif defined(USE_SELECT)
+       process_fds(socketmgr, swait->maxfd, swait->readset, swait->writeset);
+       return (ISC_R_SUCCESS);
+#endif
+}
+#endif /* ISC_PLATFORM_USETHREADS */
+
+void
+isc_socket_setname(isc_socket_t *socket, const char *name, void *tag) {
+
+       /*
+        * Name 'socket'.
+        */
+
+       REQUIRE(VALID_SOCKET(socket));
+
+       LOCK(&socket->lock);
+       memset(socket->name, 0, sizeof(socket->name));
+       strncpy(socket->name, name, sizeof(socket->name) - 1);
+       socket->tag = tag;
+       UNLOCK(&socket->lock);
+}
+
+const char *
+isc_socket_getname(isc_socket_t *socket) {
+       return (socket->name);
+}
+
+void *
+isc_socket_gettag(isc_socket_t *socket) {
+       return (socket->tag);
+}
+
+#ifdef HAVE_LIBXML2
+
+static const char *
+_socktype(isc_sockettype_t type)
+{
+       if (type == isc_sockettype_udp)
+               return ("udp");
+       else if (type == isc_sockettype_tcp)
+               return ("tcp");
+       else if (type == isc_sockettype_unix)
+               return ("unix");
+       else if (type == isc_sockettype_fdwatch)
+               return ("fdwatch");
+       else
+               return ("not-initialized");
+}
+
+void
+isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer)
+{
+       isc_socket_t *sock;
+       char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+       isc_sockaddr_t addr;
+       ISC_SOCKADDR_LEN_T len;
+
+       LOCK(&mgr->lock);
+
+#ifndef ISC_PLATFORM_USETHREADS
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
+       xmlTextWriterWriteFormatString(writer, "%d", mgr->refs);
+       xmlTextWriterEndElement(writer);
+#endif
+
+       xmlTextWriterStartElement(writer, ISC_XMLCHAR "sockets");
+       sock = ISC_LIST_HEAD(mgr->socklist);
+       while (sock != NULL) {
+               LOCK(&sock->lock);
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "socket");
+
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
+               xmlTextWriterWriteFormatString(writer, "%p", sock);
+               xmlTextWriterEndElement(writer);
+
+               if (sock->name[0] != 0) {
+                       xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
+                       xmlTextWriterWriteFormatString(writer, "%s",
+                                                      sock->name);
+                       xmlTextWriterEndElement(writer); /* name */
+               }
+
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
+               xmlTextWriterWriteFormatString(writer, "%d", sock->references);
+               xmlTextWriterEndElement(writer);
+
+               xmlTextWriterWriteElement(writer, ISC_XMLCHAR "type",
+                                         ISC_XMLCHAR _socktype(sock->type));
+
+               if (sock->connected) {
+                       isc_sockaddr_format(&sock->peer_address, peerbuf,
+                                           sizeof(peerbuf));
+                       xmlTextWriterWriteElement(writer,
+                                                 ISC_XMLCHAR "peer-address",
+                                                 ISC_XMLCHAR peerbuf);
+               }
+
+               len = sizeof(addr);
+               if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
+                       isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
+                       xmlTextWriterWriteElement(writer,
+                                                 ISC_XMLCHAR "local-address",
+                                                 ISC_XMLCHAR peerbuf);
+               }
+
+               xmlTextWriterStartElement(writer, ISC_XMLCHAR "states");
+               if (sock->pending_recv)
+                       xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
+                                               ISC_XMLCHAR "pending-receive");
+               if (sock->pending_send)
+                       xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
+                                                 ISC_XMLCHAR "pending-send");
+               if (sock->pending_accept)
+                       xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
+                                                ISC_XMLCHAR "pending_accept");
+               if (sock->listener)
+                       xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
+                                                 ISC_XMLCHAR "listener");
+               if (sock->connected)
+                       xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
+                                                 ISC_XMLCHAR "connected");
+               if (sock->connecting)
+                       xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
+                                                 ISC_XMLCHAR "connecting");
+               if (sock->bound)
+                       xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
+                                                 ISC_XMLCHAR "bound");
+
+               xmlTextWriterEndElement(writer); /* states */
+
+               xmlTextWriterEndElement(writer); /* socket */
+
+               UNLOCK(&sock->lock);
+               sock = ISC_LIST_NEXT(sock, link);
+       }
+       xmlTextWriterEndElement(writer); /* sockets */
+
+       UNLOCK(&mgr->lock);
+}
+#endif /* HAVE_LIBXML2 */
diff --git a/lib/isc/unix/socket_p.h b/lib/isc/unix/socket_p.h
new file mode 100644 (file)
index 0000000..fc044e5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: socket_p.h,v 1.13 2008/06/23 23:47:11 tbox Exp $ */
+
+#ifndef ISC_SOCKET_P_H
+#define ISC_SOCKET_P_H
+
+/*! \file */
+
+#ifdef ISC_PLATFORM_NEEDSYSSELECTH
+#include <sys/select.h>
+#endif
+
+typedef struct isc_socketwait isc_socketwait_t;
+int isc__socketmgr_waitevents(struct timeval *, isc_socketwait_t **);
+isc_result_t isc__socketmgr_dispatch(isc_socketwait_t *);
+#endif /* ISC_SOCKET_P_H */
diff --git a/lib/isc/unix/stdio.c b/lib/isc/unix/stdio.c
new file mode 100644 (file)
index 0000000..4e294db
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stdio.c,v 1.8 2007/06/19 23:47:18 tbox Exp $ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <isc/stdio.h>
+
+#include "errno2result.h"
+
+isc_result_t
+isc_stdio_open(const char *filename, const char *mode, FILE **fp) {
+       FILE *f;
+
+       f = fopen(filename, mode);
+       if (f == NULL)
+               return (isc__errno2result(errno));
+       *fp = f;
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_stdio_close(FILE *f) {
+       int r;
+
+       r = fclose(f);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_seek(FILE *f, long offset, int whence) {
+       int r;
+
+       r = fseek(f, offset, whence);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, size_t *nret) {
+       isc_result_t result = ISC_R_SUCCESS;
+       size_t r;
+
+       clearerr(f);
+       r = fread(ptr, size, nmemb, f);
+       if (r != nmemb) {
+               if (feof(f))
+                       result = ISC_R_EOF;
+               else
+                       result = isc__errno2result(errno);
+       }
+       if (nret != NULL)
+               *nret = r;
+       return (result);
+}
+
+isc_result_t
+isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f,
+              size_t *nret)
+{
+       isc_result_t result = ISC_R_SUCCESS;
+       size_t r;
+
+       clearerr(f);
+       r = fwrite(ptr, size, nmemb, f);
+       if (r != nmemb)
+               result = isc__errno2result(errno);
+       if (nret != NULL)
+               *nret = r;
+       return (result);
+}
+
+isc_result_t
+isc_stdio_flush(FILE *f) {
+       int r;
+
+       r = fflush(f);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_sync(FILE *f) {
+       int r;
+
+       r = fsync(fileno(f));
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
diff --git a/lib/isc/unix/stdtime.c b/lib/isc/unix/stdtime.c
new file mode 100644 (file)
index 0000000..c5d0c47
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stdtime.c,v 1.19 2007/06/19 23:47:18 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>    /* NULL */
+#include <stdlib.h>    /* NULL */
+#include <syslog.h>
+
+#include <sys/time.h>
+
+#include <isc/stdtime.h>
+#include <isc/util.h>
+
+#ifndef ISC_FIX_TV_USEC
+#define ISC_FIX_TV_USEC 1
+#endif
+
+#define US_PER_S 1000000
+
+#if ISC_FIX_TV_USEC
+static inline void
+fix_tv_usec(struct timeval *tv) {
+       isc_boolean_t fixed = ISC_FALSE;
+
+       if (tv->tv_usec < 0) {
+               fixed = ISC_TRUE;
+               do {
+                       tv->tv_sec -= 1;
+                       tv->tv_usec += US_PER_S;
+               } while (tv->tv_usec < 0);
+       } else if (tv->tv_usec >= US_PER_S) {
+               fixed = ISC_TRUE;
+               do {
+                       tv->tv_sec += 1;
+                       tv->tv_usec -= US_PER_S;
+               } while (tv->tv_usec >=US_PER_S);
+       }
+       /*
+        * Call syslog directly as we are called from the logging functions.
+        */
+       if (fixed)
+               (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
+}
+#endif
+
+void
+isc_stdtime_get(isc_stdtime_t *t) {
+       struct timeval tv;
+
+       /*
+        * Set 't' to the number of seconds since 00:00:00 UTC, January 1,
+        * 1970.
+        */
+
+       REQUIRE(t != NULL);
+
+       RUNTIME_CHECK(gettimeofday(&tv, NULL) != -1);
+
+#if ISC_FIX_TV_USEC
+       fix_tv_usec(&tv);
+       INSIST(tv.tv_usec >= 0);
+#else
+       INSIST(tv.tv_usec >= 0 && tv.tv_usec < US_PER_S);
+#endif
+
+       *t = (unsigned int)tv.tv_sec;
+}
index 9ec4a2f1535ac9169a0fccf6d94af9d0ad4cf667..349c8bd92cf7b6340d60556f373d0a7f211fc3f3 100644 (file)
@@ -1,21 +1,23 @@
 /*
+ * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: strerror.c,v 1.3 2001/11/20 01:45:45 gson Exp $ */
+/* $Id: strerror.c,v 1.8.332.2 2009/02/16 23:47:15 tbox Exp $ */
+
+/*! \file */
 
 #include <config.h>
 
 #include <isc/strerror.h>
 #include <isc/util.h>
 
-#include "l_stdlib.h"
-
 #ifdef HAVE_STRERROR
-/*
+/*%
  * We need to do this this way for profiled locks.
  */
 static isc_mutex_t isc_strerror_lock;
@@ -47,7 +47,7 @@ void
 isc__strerror(int num, char *buf, size_t size) {
 #ifdef HAVE_STRERROR
        char *msg;
-       unsigned int unum = num;
+       unsigned int unum = (unsigned int)num;
        static isc_once_t once = ISC_ONCE_INIT;
 
        REQUIRE(buf != NULL);
@@ -62,7 +62,7 @@ isc__strerror(int num, char *buf, size_t size) {
                snprintf(buf, size, "Unknown error: %u", unum);
        UNLOCK(&isc_strerror_lock);
 #else
-       unsigned int unum = num;
+       unsigned int unum = (unsigned int)num;
 
        REQUIRE(buf != NULL);
 
diff --git a/lib/isc/unix/syslog.c b/lib/isc/unix/syslog.c
new file mode 100644 (file)
index 0000000..997508e
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: syslog.c,v 1.8 2007/09/13 04:45:18 each Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/syslog.h>
+#include <isc/util.h>
+
+static struct dsn_c_pvt_sfnt {
+       int val;
+       const char *strval;
+} facilities[] = {
+       { LOG_KERN,                     "kern" },
+       { LOG_USER,                     "user" },
+       { LOG_MAIL,                     "mail" },
+       { LOG_DAEMON,                   "daemon" },
+       { LOG_AUTH,                     "auth" },
+       { LOG_SYSLOG,                   "syslog" },
+       { LOG_LPR,                      "lpr" },
+#ifdef LOG_NEWS
+       { LOG_NEWS,                     "news" },
+#endif
+#ifdef LOG_UUCP
+       { LOG_UUCP,                     "uucp" },
+#endif
+#ifdef LOG_CRON
+       { LOG_CRON,                     "cron" },
+#endif
+#ifdef LOG_AUTHPRIV
+       { LOG_AUTHPRIV,                 "authpriv" },
+#endif
+#ifdef LOG_FTP
+       { LOG_FTP,                      "ftp" },
+#endif
+       { LOG_LOCAL0,                   "local0"},
+       { LOG_LOCAL1,                   "local1"},
+       { LOG_LOCAL2,                   "local2"},
+       { LOG_LOCAL3,                   "local3"},
+       { LOG_LOCAL4,                   "local4"},
+       { LOG_LOCAL5,                   "local5"},
+       { LOG_LOCAL6,                   "local6"},
+       { LOG_LOCAL7,                   "local7"},
+       { 0,                            NULL }
+};
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp) {
+       int i;
+
+       REQUIRE(str != NULL);
+       REQUIRE(facilityp != NULL);
+
+       for (i = 0; facilities[i].strval != NULL; i++) {
+               if (strcasecmp(facilities[i].strval, str) == 0) {
+                       *facilityp = facilities[i].val;
+                       return (ISC_R_SUCCESS);
+               }
+       }
+       return (ISC_R_NOTFOUND);
+
+}
diff --git a/lib/isc/unix/time.c b/lib/isc/unix/time.c
new file mode 100644 (file)
index 0000000..59428d3
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: time.c,v 1.56 2008/02/15 23:46:51 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <sys/time.h>  /* Required for struct timeval on some platforms. */
+
+#include <isc/log.h>
+#include <isc/print.h>
+#include <isc/strerror.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#define NS_PER_S       1000000000      /*%< Nanoseconds per second. */
+#define NS_PER_US      1000            /*%< Nanoseconds per microsecond. */
+#define US_PER_S       1000000         /*%< Microseconds per second. */
+
+/*
+ * All of the INSIST()s checks of nanoseconds < NS_PER_S are for
+ * consistency checking of the type. In lieu of magic numbers, it
+ * is the best we've got.  The check is only performed on functions which
+ * need an initialized type.
+ */
+
+#ifndef ISC_FIX_TV_USEC
+#define ISC_FIX_TV_USEC 1
+#endif
+
+/*%
+ *** Intervals
+ ***/
+
+static isc_interval_t zero_interval = { 0, 0 };
+isc_interval_t *isc_interval_zero = &zero_interval;
+
+#if ISC_FIX_TV_USEC
+static inline void
+fix_tv_usec(struct timeval *tv) {
+       isc_boolean_t fixed = ISC_FALSE;
+
+       if (tv->tv_usec < 0) {
+               fixed = ISC_TRUE;
+               do {
+                       tv->tv_sec -= 1;
+                       tv->tv_usec += US_PER_S;
+               } while (tv->tv_usec < 0);
+       } else if (tv->tv_usec >= US_PER_S) {
+               fixed = ISC_TRUE;
+               do {
+                       tv->tv_sec += 1;
+                       tv->tv_usec -= US_PER_S;
+               } while (tv->tv_usec >=US_PER_S);
+       }
+       /*
+        * Call syslog directly as was are called from the logging functions.
+        */
+       if (fixed)
+               (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
+}
+#endif
+
+void
+isc_interval_set(isc_interval_t *i,
+                unsigned int seconds, unsigned int nanoseconds)
+{
+       REQUIRE(i != NULL);
+       REQUIRE(nanoseconds < NS_PER_S);
+
+       i->seconds = seconds;
+       i->nanoseconds = nanoseconds;
+}
+
+isc_boolean_t
+isc_interval_iszero(const isc_interval_t *i) {
+       REQUIRE(i != NULL);
+       INSIST(i->nanoseconds < NS_PER_S);
+
+       if (i->seconds == 0 && i->nanoseconds == 0)
+               return (ISC_TRUE);
+
+       return (ISC_FALSE);
+}
+
+
+/***
+ *** Absolute Times
+ ***/
+
+static isc_time_t epoch = { 0, 0 };
+isc_time_t *isc_time_epoch = &epoch;
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
+       REQUIRE(t != NULL);
+       REQUIRE(nanoseconds < NS_PER_S);
+
+       t->seconds = seconds;
+       t->nanoseconds = nanoseconds;
+}
+
+void
+isc_time_settoepoch(isc_time_t *t) {
+       REQUIRE(t != NULL);
+
+       t->seconds = 0;
+       t->nanoseconds = 0;
+}
+
+isc_boolean_t
+isc_time_isepoch(const isc_time_t *t) {
+       REQUIRE(t != NULL);
+       INSIST(t->nanoseconds < NS_PER_S);
+
+       if (t->seconds == 0 && t->nanoseconds == 0)
+               return (ISC_TRUE);
+
+       return (ISC_FALSE);
+}
+
+
+isc_result_t
+isc_time_now(isc_time_t *t) {
+       struct timeval tv;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(t != NULL);
+
+       if (gettimeofday(&tv, NULL) == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
+               return (ISC_R_UNEXPECTED);
+       }
+
+       /*
+        * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
+        * then this test will generate warnings for platforms on which it is
+        * unsigned.  In any event, the chances of any of these problems
+        * happening are pretty much zero, but since the libisc library ensures
+        * certain things to be true ...
+        */
+#if ISC_FIX_TV_USEC
+       fix_tv_usec(&tv);
+       if (tv.tv_sec < 0)
+               return (ISC_R_UNEXPECTED);
+#else
+       if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
+               return (ISC_R_UNEXPECTED);
+#endif
+
+       /*
+        * Ensure the tv_sec value fits in t->seconds.
+        */
+       if (sizeof(tv.tv_sec) > sizeof(t->seconds) &&
+           ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U)
+               return (ISC_R_RANGE);
+
+       t->seconds = tv.tv_sec;
+       t->nanoseconds = tv.tv_usec * NS_PER_US;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
+       struct timeval tv;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(t != NULL);
+       REQUIRE(i != NULL);
+       INSIST(i->nanoseconds < NS_PER_S);
+
+       if (gettimeofday(&tv, NULL) == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
+               return (ISC_R_UNEXPECTED);
+       }
+
+       /*
+        * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
+        * then this test will generate warnings for platforms on which it is
+        * unsigned.  In any event, the chances of any of these problems
+        * happening are pretty much zero, but since the libisc library ensures
+        * certain things to be true ...
+        */
+#if ISC_FIX_TV_USEC
+       fix_tv_usec(&tv);
+       if (tv.tv_sec < 0)
+               return (ISC_R_UNEXPECTED);
+#else
+       if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
+               return (ISC_R_UNEXPECTED);
+#endif
+
+       /*
+        * Ensure the resulting seconds value fits in the size of an
+        * unsigned int.  (It is written this way as a slight optimization;
+        * note that even if both values == INT_MAX, then when added
+        * and getting another 1 added below the result is UINT_MAX.)
+        */
+       if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
+           ((long long)tv.tv_sec + i->seconds > UINT_MAX))
+               return (ISC_R_RANGE);
+
+       t->seconds = tv.tv_sec + i->seconds;
+       t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds;
+       if (t->nanoseconds >= NS_PER_S) {
+               t->seconds++;
+               t->nanoseconds -= NS_PER_S;
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
+       REQUIRE(t1 != NULL && t2 != NULL);
+       INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
+
+       if (t1->seconds < t2->seconds)
+               return (-1);
+       if (t1->seconds > t2->seconds)
+               return (1);
+       if (t1->nanoseconds < t2->nanoseconds)
+               return (-1);
+       if (t1->nanoseconds > t2->nanoseconds)
+               return (1);
+       return (0);
+}
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
+{
+       REQUIRE(t != NULL && i != NULL && result != NULL);
+       INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
+
+       /*
+        * Ensure the resulting seconds value fits in the size of an
+        * unsigned int.  (It is written this way as a slight optimization;
+        * note that even if both values == INT_MAX, then when added
+        * and getting another 1 added below the result is UINT_MAX.)
+        */
+       if ((t->seconds > INT_MAX || i->seconds > INT_MAX) &&
+           ((long long)t->seconds + i->seconds > UINT_MAX))
+               return (ISC_R_RANGE);
+
+       result->seconds = t->seconds + i->seconds;
+       result->nanoseconds = t->nanoseconds + i->nanoseconds;
+       if (result->nanoseconds >= NS_PER_S) {
+               result->seconds++;
+               result->nanoseconds -= NS_PER_S;
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+                 isc_time_t *result)
+{
+       REQUIRE(t != NULL && i != NULL && result != NULL);
+       INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
+
+       if ((unsigned int)t->seconds < i->seconds ||
+           ((unsigned int)t->seconds == i->seconds &&
+            t->nanoseconds < i->nanoseconds))
+           return (ISC_R_RANGE);
+
+       result->seconds = t->seconds - i->seconds;
+       if (t->nanoseconds >= i->nanoseconds)
+               result->nanoseconds = t->nanoseconds - i->nanoseconds;
+       else {
+               result->nanoseconds = NS_PER_S - i->nanoseconds +
+                       t->nanoseconds;
+               result->seconds--;
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
+       isc_uint64_t i1, i2, i3;
+
+       REQUIRE(t1 != NULL && t2 != NULL);
+       INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
+
+       i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds;
+       i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds;
+
+       if (i1 <= i2)
+               return (0);
+
+       i3 = i1 - i2;
+
+       /*
+        * Convert to microseconds.
+        */
+       i3 = (i1 - i2) / NS_PER_US;
+
+       return (i3);
+}
+
+isc_uint32_t
+isc_time_seconds(const isc_time_t *t) {
+       REQUIRE(t != NULL);
+       INSIST(t->nanoseconds < NS_PER_S);
+
+       return ((isc_uint32_t)t->seconds);
+}
+
+isc_result_t
+isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
+       isc_uint64_t i;
+       time_t seconds;
+
+       REQUIRE(t != NULL);
+       INSIST(t->nanoseconds < NS_PER_S);
+
+       /*
+        * Ensure that the number of seconds represented by t->seconds
+        * can be represented by a time_t.  Since t->seconds is an unsigned
+        * int and since time_t is mostly opaque, this is trickier than
+        * it seems.  (This standardized opaqueness of time_t is *very*
+        * frustrating; time_t is not even limited to being an integral
+        * type.)
+        *
+        * The mission, then, is to avoid generating any kind of warning
+        * about "signed versus unsigned" while trying to determine if the
+        * the unsigned int t->seconds is out range for tv_sec, which is
+        * pretty much only true if time_t is a signed integer of the same
+        * size as the return value of isc_time_seconds.
+        *
+        * The use of the 64 bit integer ``i'' takes advantage of C's
+        * conversion rules to either zero fill or sign extend the widened
+        * type.
+        *
+        * Solaris 5.6 gives this warning about the left shift:
+        *      warning: integer overflow detected: op "<<"
+        * if the U(nsigned) qualifier is not on the 1.
+        */
+       seconds = (time_t)t->seconds;
+
+       INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t));
+       INSIST(sizeof(time_t) >= sizeof(isc_uint32_t));
+
+       if (sizeof(time_t) == sizeof(isc_uint32_t) &&          /* Same size. */
+           (time_t)0.5 != 0.5 &&              /* Not a floating point type. */
+           (i = (time_t)-1) != 4294967295u &&                 /* Is signed. */
+           (seconds &
+            (1U << (sizeof(time_t) * CHAR_BIT - 1))) != 0U) {   /* Negative. */
+               /*
+                * This UNUSED() is here to shut up the IRIX compiler:
+                *      variable "i" was set but never used
+                * when the value of i *was* used in the third test.
+                * (Let's hope the compiler got the actual test right.)
+                */
+               UNUSED(i);
+               return (ISC_R_RANGE);
+       }
+
+       *secondsp = seconds;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_uint32_t
+isc_time_nanoseconds(const isc_time_t *t) {
+       REQUIRE(t != NULL);
+
+       ENSURE(t->nanoseconds < NS_PER_S);
+
+       return ((isc_uint32_t)t->nanoseconds);
+}
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+       time_t now;
+       unsigned int flen;
+
+       REQUIRE(len > 0);
+
+       now = (time_t) t->seconds;
+       flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now));
+       INSIST(flen < len);
+       if (flen != 0)
+               snprintf(buf + flen, len - flen,
+                        ".%03u", t->nanoseconds / 1000000);
+       else
+               snprintf(buf, len, "99-Bad-9999 99:99:99.999");
+}
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+       time_t now;
+       unsigned int flen;
+
+       REQUIRE(len > 0);
+
+       now = (time_t)t->seconds;
+       flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
+       INSIST(flen < len);
+}
+
+void
+isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
+       time_t now;
+       unsigned int flen;
+
+       REQUIRE(len > 0);
+
+       now = (time_t)t->seconds;
+       flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
+       INSIST(flen < len);
+}
diff --git a/lib/isc/version.c b/lib/isc/version.c
new file mode 100644 (file)
index 0000000..bfe4d6d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: version.c,v 1.15 2007/06/19 23:47:17 tbox Exp $ */
+
+/*! \file */
+
+#include <isc/version.h>
+
+const char isc_version[] = VERSION;
+
+const unsigned int isc_libinterface = LIBINTERFACE;
+const unsigned int isc_librevision = LIBREVISION;
+const unsigned int isc_libage = LIBAGE;
diff --git a/lib/isc/win32/DLLMain.c b/lib/isc/win32/DLLMain.c
new file mode 100644 (file)
index 0000000..ed84fcf
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: DLLMain.c,v 1.7 2007/06/18 23:47:49 tbox Exp $ */
+
+#include <windows.h>
+#include <stdio.h>
+
+/*
+ * Called when we enter the DLL
+ */
+__declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL,
+                                         DWORD fdwReason, LPVOID lpvReserved)
+{
+       switch (fdwReason) 
+       { 
+       /*
+        * The DLL is loading due to process 
+        * initialization or a call to LoadLibrary. 
+        */
+       case DLL_PROCESS_ATTACH: 
+               break; 
+       /* The attached process creates a new thread.  */
+       case DLL_THREAD_ATTACH: 
+               break; 
+       /* The thread of the attached process terminates. */
+       case DLL_THREAD_DETACH: 
+               break; 
+       /*
+        * The DLL is unloading from a process due to 
+        * process termination or a call to FreeLibrary. 
+        */
+       case DLL_PROCESS_DETACH: 
+               break; 
+
+       default: 
+               break; 
+       } 
+       return (TRUE);
+}
+
diff --git a/lib/isc/win32/app.c b/lib/isc/win32/app.c
new file mode 100644 (file)
index 0000000..b0db90d
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: app.c,v 1.7 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <process.h>
+
+#include <isc/app.h>
+#include <isc/boolean.h>
+#include <isc/condition.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/event.h>
+#include <isc/platform.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+#include <isc/thread.h>
+
+static isc_eventlist_t on_run;
+static isc_mutex_t     lock;
+static isc_boolean_t   shutdown_requested = ISC_FALSE;
+static isc_boolean_t   running = ISC_FALSE;
+/*
+ * We assume that 'want_shutdown' can be read and written atomically.
+ */
+static isc_boolean_t   want_shutdown = ISC_FALSE;
+/*
+ * We assume that 'want_reload' can be read and written atomically.
+ */
+static isc_boolean_t   want_reload = ISC_FALSE;
+
+static isc_boolean_t   blocked  = ISC_FALSE;
+
+static isc_thread_t    blockedthread;
+
+/* Events to wait for */
+
+#define NUM_EVENTS 2
+
+enum {
+       RELOAD_EVENT,
+       SHUTDOWN_EVENT
+};
+
+static HANDLE hEvents[NUM_EVENTS];
+DWORD  dwWaitResult;
+
+/*
+ * We need to remember which thread is the main thread...
+ */
+static isc_thread_t    main_thread;
+
+isc_result_t
+isc_app_start(void) {
+       isc_result_t result;
+
+       /*
+        * Start an ISC library application.
+        */
+
+       main_thread = GetCurrentThread();
+
+       result = isc_mutex_init(&lock);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       /* Create the reload event in a non-signaled state */
+       hEvents[RELOAD_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+       /* Create the shutdown event in a non-signaled state */
+       hEvents[SHUTDOWN_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+       ISC_LIST_INIT(on_run);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
+             void *arg) {
+       isc_event_t *event;
+       isc_task_t *cloned_task = NULL;
+       isc_result_t result;
+
+
+       LOCK(&lock);
+       if (running) {
+               result = ISC_R_ALREADYRUNNING;
+               goto unlock;
+       }
+
+       /*
+        * Note that we store the task to which we're going to send the event
+        * in the event's "sender" field.
+        */
+       isc_task_attach(task, &cloned_task);
+       event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN,
+                                  action, arg, sizeof(*event));
+       if (event == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto unlock;
+       }
+
+       ISC_LIST_APPEND(on_run, event, ev_link);
+       result = ISC_R_SUCCESS;
+
+ unlock:
+       UNLOCK(&lock);
+       return (result);
+}
+
+isc_result_t
+isc_app_run(void) {
+       isc_event_t *event, *next_event;
+       isc_task_t *task;
+       HANDLE *pHandles = NULL;
+
+       REQUIRE(main_thread == GetCurrentThread());
+       LOCK(&lock);
+       if (!running) {
+               running = ISC_TRUE;
+
+               /*
+                * Post any on-run events (in FIFO order).
+                */
+               for (event = ISC_LIST_HEAD(on_run);
+                    event != NULL;
+                    event = next_event) {
+                       next_event = ISC_LIST_NEXT(event, ev_link);
+                       ISC_LIST_UNLINK(on_run, event, ev_link);
+                       task = event->ev_sender;
+                       event->ev_sender = NULL;
+                       isc_task_sendanddetach(&task, &event);
+               }
+
+       }
+
+       UNLOCK(&lock);
+
+       /*
+        * There is no danger if isc_app_shutdown() is called before we wait
+        * for events.
+        */
+
+       while (!want_shutdown) {
+               dwWaitResult = WaitForMultipleObjects(NUM_EVENTS, hEvents,
+                                                     FALSE, INFINITE);
+
+               /* See why we returned */
+               
+               if (WaitSucceeded(dwWaitResult, NUM_EVENTS)) {
+                       /*
+                        * The return was due to one of the events
+                        * being signaled
+                        */
+                       switch (WaitSucceededIndex(dwWaitResult)) {
+                       case RELOAD_EVENT:
+                               want_reload = ISC_TRUE;
+                               break;
+
+                       case SHUTDOWN_EVENT:
+                               want_shutdown = ISC_TRUE;
+                               break;
+                       }
+               }
+               if (want_reload) {
+                       want_reload = ISC_FALSE;
+                       return (ISC_R_RELOAD);
+               }
+
+               if (want_shutdown && blocked)
+                       exit(-1);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_shutdown(void) {
+       isc_boolean_t want_kill = ISC_TRUE;
+
+       LOCK(&lock);
+       REQUIRE(running);
+
+       if (shutdown_requested)
+               want_kill = ISC_FALSE;          /* We're only signaling once */
+       else
+               shutdown_requested = ISC_TRUE;
+
+       UNLOCK(&lock);
+       if (want_kill)
+               SetEvent(hEvents[SHUTDOWN_EVENT]);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_app_reload(void) {
+       isc_boolean_t want_reload = ISC_TRUE;
+
+       LOCK(&lock);
+       REQUIRE(running);
+
+       /*
+        * Don't send the reload signal if we're shutting down.
+        */
+       if (shutdown_requested)
+               want_reload = ISC_FALSE;
+
+       UNLOCK(&lock);
+       if (want_reload)
+               SetEvent(hEvents[RELOAD_EVENT]);
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_app_finish(void) {
+       DESTROYLOCK(&lock);
+}
+
+void
+isc_app_block(void) {
+       REQUIRE(running);
+       REQUIRE(!blocked);
+
+       blocked = ISC_TRUE;
+       blockedthread = GetCurrentThread();
+}
+
+void
+isc_app_unblock(void) {
+       REQUIRE(running);
+       REQUIRE(blocked);
+       blocked = ISC_FALSE;
+       REQUIRE(blockedthread == GetCurrentThread());
+}
diff --git a/lib/isc/win32/condition.c b/lib/isc/win32/condition.c
new file mode 100644 (file)
index 0000000..27d4e76
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2004, 2006, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: condition.c,v 1.23 2007/06/18 23:47:49 tbox Exp $ */
+
+#include <config.h>
+
+#include <isc/condition.h>
+#include <isc/assertions.h>
+#include <isc/util.h>
+#include <isc/thread.h>
+#include <isc/time.h>
+
+#define LSIGNAL                0
+#define LBROADCAST     1
+
+isc_result_t
+isc_condition_init(isc_condition_t *cond) {
+       HANDLE h;
+
+       REQUIRE(cond != NULL);
+
+       cond->waiters = 0;
+       /*
+        * This handle is shared across all threads
+        */
+       h = CreateEvent(NULL, FALSE, FALSE, NULL);
+       if (h == NULL) {
+               /* XXX */
+               return (ISC_R_UNEXPECTED);
+       }
+       cond->events[LSIGNAL] = h;
+
+       /*
+        * The threadlist will hold the actual events needed
+        * for the wait condition
+        */
+       ISC_LIST_INIT(cond->threadlist);
+
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * Add the thread to the threadlist along with the required events
+ */
+static isc_result_t
+register_thread(unsigned long thrd, isc_condition_t *gblcond,
+               isc_condition_thread_t **localcond)
+{
+       HANDLE hc;
+       isc_condition_thread_t *newthread;
+
+       REQUIRE(localcond != NULL && *localcond == NULL);
+
+       newthread = malloc(sizeof(isc_condition_thread_t));
+       if (newthread == NULL)
+               return (ISC_R_NOMEMORY);
+
+       /*
+        * Create the thread-specific handle
+        */
+       hc = CreateEvent(NULL, FALSE, FALSE, NULL);
+       if (hc == NULL) {
+               free(newthread);
+               return (ISC_R_UNEXPECTED);
+       }
+
+       /*
+        * Add the thread ID and handles to list of threads for broadcast
+        */
+       newthread->handle[LSIGNAL] = gblcond->events[LSIGNAL];
+       newthread->handle[LBROADCAST] = hc;
+       newthread->th = thrd;
+
+       /*
+        * The thread is holding the manager lock so this is safe
+        */
+       ISC_LIST_APPEND(gblcond->threadlist, newthread, link);
+       *localcond = newthread;
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+find_thread_condition(unsigned long thrd, isc_condition_t *cond,
+                     isc_condition_thread_t **threadcondp)
+{
+       isc_condition_thread_t *threadcond;
+
+       REQUIRE(threadcondp != NULL && *threadcondp == NULL);
+
+       /*
+        * Look for the thread ID.
+        */
+       for (threadcond = ISC_LIST_HEAD(cond->threadlist);
+            threadcond != NULL;
+            threadcond = ISC_LIST_NEXT(threadcond, link)) {
+
+               if (threadcond->th == thrd) {
+                       *threadcondp = threadcond;
+                       return (ISC_R_SUCCESS);
+               }
+       }
+
+       /*
+        * Not found, so add it.
+        */
+       return (register_thread(thrd, cond, threadcondp));
+}
+
+isc_result_t
+isc_condition_signal(isc_condition_t *cond) {
+
+       /*
+        * Unlike pthreads, the caller MUST hold the lock associated with
+        * the condition variable when calling us.
+        */
+       REQUIRE(cond != NULL);
+
+       if (!SetEvent(cond->events[LSIGNAL])) {
+               /* XXX */
+               return (ISC_R_UNEXPECTED);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_condition_broadcast(isc_condition_t *cond) {
+
+       isc_condition_thread_t *threadcond;
+       isc_boolean_t failed = ISC_FALSE;
+
+       /*
+        * Unlike pthreads, the caller MUST hold the lock associated with
+        * the condition variable when calling us.
+        */
+       REQUIRE(cond != NULL);
+
+       /*
+        * Notify every thread registered for this
+        */
+       for (threadcond = ISC_LIST_HEAD(cond->threadlist);
+            threadcond != NULL;
+            threadcond = ISC_LIST_NEXT(threadcond, link)) {
+
+               if (!SetEvent(threadcond->handle[LBROADCAST]))
+                       failed = ISC_TRUE;
+       }
+
+       if (failed)
+               return (ISC_R_UNEXPECTED);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_condition_destroy(isc_condition_t *cond) {
+
+       isc_condition_thread_t *next, *threadcond;
+
+       REQUIRE(cond != NULL);
+       REQUIRE(cond->waiters == 0);
+
+       (void)CloseHandle(cond->events[LSIGNAL]);
+
+       /*
+        * Delete the threadlist
+        */
+       threadcond = ISC_LIST_HEAD(cond->threadlist);
+
+       while (threadcond != NULL) {
+               next = ISC_LIST_NEXT(threadcond, link);
+               DEQUEUE(cond->threadlist, threadcond, link);
+               (void) CloseHandle(threadcond->handle[LBROADCAST]);
+               free(threadcond);
+               threadcond = next;
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * This is always called when the mutex (lock) is held, but because
+ * we are waiting we need to release it and reacquire it as soon as the wait
+ * is over. This allows other threads to make use of the object guarded
+ * by the mutex but it should never try to delete it as long as the
+ * number of waiters > 0. Always reacquire the mutex regardless of the
+ * result of the wait. Note that EnterCriticalSection will wait to acquire
+ * the mutex.
+ */
+static isc_result_t
+wait(isc_condition_t *cond, isc_mutex_t *mutex, DWORD milliseconds) {
+       DWORD result;
+       isc_result_t tresult;
+       isc_condition_thread_t *threadcond = NULL;
+
+       /*
+        * Get the thread events needed for the wait
+        */
+       tresult = find_thread_condition(isc_thread_self(), cond, &threadcond);
+       if (tresult !=  ISC_R_SUCCESS)
+               return (tresult);
+
+       cond->waiters++;
+       LeaveCriticalSection(mutex);
+       result = WaitForMultipleObjects(2, threadcond->handle, FALSE,
+                                       milliseconds);
+       EnterCriticalSection(mutex);
+       cond->waiters--;
+       if (result == WAIT_FAILED) {
+               /* XXX */
+               return (ISC_R_UNEXPECTED);
+       }
+       if (result == WAIT_TIMEOUT)
+               return (ISC_R_TIMEDOUT);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_condition_wait(isc_condition_t *cond, isc_mutex_t *mutex) {
+       return (wait(cond, mutex, INFINITE));
+}
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *cond, isc_mutex_t *mutex,
+                       isc_time_t *t) {
+       DWORD milliseconds;
+       isc_uint64_t microseconds;
+       isc_time_t now;
+
+       if (isc_time_now(&now) != ISC_R_SUCCESS) {
+               /* XXX */
+               return (ISC_R_UNEXPECTED);
+       }
+
+       microseconds = isc_time_microdiff(t, &now);
+       if (microseconds > 0xFFFFFFFFi64 * 1000)
+               milliseconds = 0xFFFFFFFF;
+       else
+               milliseconds = (DWORD)(microseconds / 1000);
+
+       return (wait(cond, mutex, milliseconds));
+}
diff --git a/lib/isc/win32/dir.c b/lib/isc/win32/dir.c
new file mode 100644 (file)
index 0000000..cbeacba
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2004, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dir.c,v 1.16.22.2 2009/01/18 23:47:41 tbox Exp $ */
+
+/* Principal Authors: DCL */
+
+#include <config.h>
+
+#include <string.h>
+#include <direct.h>
+#include <process.h>
+#include <io.h>
+
+#include <sys/stat.h>
+
+#include <isc/dir.h>
+#include <isc/magic.h>
+#include <isc/assertions.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+#define ISC_DIR_MAGIC          ISC_MAGIC('D', 'I', 'R', '*')
+#define VALID_DIR(dir)         ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
+
+static isc_result_t
+start_directory(isc_dir_t *p);
+
+void
+isc_dir_init(isc_dir_t *dir) {
+       REQUIRE(dir != NULL);
+
+       dir->dirname[0] = '\0';
+
+       dir->entry.name[0] = '\0';
+       dir->entry.length = 0;
+       memset(&(dir->entry.find_data), 0, sizeof(dir->entry.find_data));
+
+       dir->entry_filled = ISC_FALSE;
+       dir->search_handle = INVALID_HANDLE_VALUE;
+
+       dir->magic = ISC_DIR_MAGIC;
+}
+
+/*
+ * Allocate workspace and open directory stream. If either one fails,
+ * NULL will be returned.
+ */
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname) {
+       char *p;
+       isc_result_t result;
+
+       REQUIRE(dirname != NULL);
+       REQUIRE(VALID_DIR(dir) && dir->search_handle == INVALID_HANDLE_VALUE);
+
+       /*
+        * Copy directory name.  Need to have enough space for the name,
+        * a possible path separator, the wildcard, and the final NUL.
+        */
+       if (strlen(dirname) + 3 > sizeof(dir->dirname))
+               /* XXXDCL ? */
+               return (ISC_R_NOSPACE);
+       strcpy(dir->dirname, dirname);
+
+       /*
+        * Append path separator, if needed, and "*".
+        */
+       p = dir->dirname + strlen(dir->dirname);
+       if (dir->dirname < p && *(p - 1) != '\\' && *(p - 1) != ':')
+               *p++ = '\\';
+       *p++ = '*';
+       *p++ = '\0';
+
+       /*
+        * Open stream.
+        */
+       result = start_directory(dir);
+
+       return (result);
+}
+
+/*
+ * Return previously retrieved file or get next one.  Unix's dirent has
+ * separate open and read functions, but the Win32 and DOS interfaces open
+ * the dir stream and reads the first file in one operation.
+ */
+isc_result_t
+isc_dir_read(isc_dir_t *dir) {
+       REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE);
+
+       if (dir->entry_filled)
+               /*
+                * start_directory() already filled in the first entry.
+                */
+               dir->entry_filled = ISC_FALSE;
+
+       else {
+               /*
+                * Fetch next file in directory.
+                */
+               if (FindNextFile(dir->search_handle,
+                                &dir->entry.find_data) == FALSE)
+                       /*
+                        * Either the last file has been processed or
+                        * an error has occurred.  The former is not
+                        * really an error, but the latter is.
+                        */
+                       if (GetLastError() == ERROR_NO_MORE_FILES)
+                               return (ISC_R_NOMORE);
+                       else
+                               return (ISC_R_UNEXPECTED);
+       }
+
+       /*
+        * Make sure that the space for the name is long enough.
+        */
+       strcpy(dir->entry.name, dir->entry.find_data.cFileName);
+       dir->entry.length = strlen(dir->entry.name);
+
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * Close directory stream.
+ */
+void
+isc_dir_close(isc_dir_t *dir) {
+       REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE);
+
+       FindClose(dir->search_handle);
+       dir->search_handle = INVALID_HANDLE_VALUE;
+}
+
+/*
+ * Reposition directory stream at start.
+ */
+isc_result_t
+isc_dir_reset(isc_dir_t *dir) {
+       isc_result_t result;
+
+       REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE);
+       REQUIRE(dir->dirname != NULL);
+
+       /*
+        * NT cannot reposition the seek pointer to the beginning of the
+        * the directory stream, but rather the directory needs to be
+        * closed and reopened.  The latter might fail.
+        */
+
+       isc_dir_close(dir);
+
+       result = start_directory(dir);
+
+       return (result);
+}
+
+/*
+ * Initialize isc_dir_t structure with new directory. The function
+ * returns 0 on failure and nonzero on success.
+ *
+ * Note:
+ * - Be sure to close previous stream before opening new one
+ */
+static isc_result_t
+start_directory(isc_dir_t *dir)
+{
+       REQUIRE(VALID_DIR(dir));
+       REQUIRE(dir->search_handle == INVALID_HANDLE_VALUE);
+
+       dir->entry_filled = ISC_FALSE;
+
+       /*
+        * Open stream and retrieve first file.
+        */
+       dir->search_handle = FindFirstFile(dir->dirname,
+                                           &dir->entry.find_data);
+
+       if (dir->search_handle == INVALID_HANDLE_VALUE) {
+               /*
+                * Something went wrong but we don't know what. GetLastError()
+                * could give us more information about the error, but the
+                * MSDN documentation is frustratingly thin about what
+                * possible errors could have resulted.  (Score one for
+                * the Unix manual pages.)  So there is just this lame error
+                * instead of being able to differentiate ISC_R_NOTFOUND
+                * from ISC_R_UNEXPECTED.
+                */
+               return (ISC_R_FAILURE);
+       }
+
+       /*
+        * Make sure that the space for the name is long enough.
+        */
+       INSIST(sizeof(dir->entry.name) >
+              strlen(dir->entry.find_data.cFileName));
+
+       /*
+        * Fill in the data for the first entry of the directory.
+        */
+       strcpy(dir->entry.name, dir->entry.find_data.cFileName);
+       dir->entry.length = strlen(dir->entry.name);
+
+       dir->entry_filled = ISC_TRUE;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chdir(const char *dirname) {
+       /*
+        * Change the current directory to 'dirname'.
+        */
+
+       REQUIRE(dirname != NULL);
+
+       if (chdir(dirname) < 0)
+               return (isc__errno2result(errno));
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chroot(const char *dirname) {
+       return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+isc_dir_createunique(char *templet) {
+       isc_result_t result;
+       char *x;
+       char *p;
+       int i;
+       int pid;
+
+       REQUIRE(templet != NULL);
+
+       /*
+        * mkdtemp is not portable, so this emulates it.
+        */
+
+       pid = getpid();
+
+       /*
+        * Replace trailing Xs with the process-id, zero-filled.
+        */
+       for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet;
+            x--, pid /= 10)
+               *x = pid % 10 + '0';
+
+       x++;                    /* Set x to start of ex-Xs. */
+
+       do {
+               i = mkdir(templet);
+               i = chmod(templet, 0700);
+
+               if (i == 0 || errno != EEXIST)
+                       break;
+
+               /*
+                * The BSD algorithm.
+                */
+               p = x;
+               while (*p != '\0') {
+                       if (isdigit(*p & 0xff))
+                               *p = 'a';
+                       else if (*p != 'z')
+                               ++*p;
+                       else {
+                               /*
+                                * Reset character and move to next.
+                                */
+                               *p++ = 'a';
+                               continue;
+                       }
+
+                       break;
+               }
+
+               if (*p == '\0') {
+                       /*
+                        * Tried all combinations.  errno should already
+                        * be EEXIST, but ensure it is anyway for
+                        * isc__errno2result().
+                        */
+                       errno = EEXIST;
+                       break;
+               }
+       } while (1);
+
+       if (i == -1)
+               result = isc__errno2result(errno);
+       else
+               result = ISC_R_SUCCESS;
+
+       return (result);
+}
diff --git a/lib/isc/win32/entropy.c b/lib/isc/win32/entropy.c
new file mode 100644 (file)
index 0000000..7f4bb3f
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2004, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: entropy.c,v 1.8.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+/*
+ * This is the system dependent part of the ISC entropy API.
+ */
+
+#include <config.h>
+
+#include <windows.h>
+#include <wincrypt.h>
+
+#include <process.h>
+#include <io.h>
+#include <share.h>
+
+/*
+ * There is only one variable in the entropy data structures that is not
+ * system independent, but pulling the structure that uses it into this file
+ * ultimately means pulling several other independent structures here also to
+ * resolve their interdependencies.  Thus only the problem variable's type
+ * is defined here.
+ */
+#define FILESOURCE_HANDLE_TYPE HCRYPTPROV
+
+typedef struct {
+       int dummy;
+} isc_entropyusocketsource_t;
+
+#include "../entropy.c"
+
+static unsigned int
+get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
+       isc_entropy_t *ent = source->ent;
+       unsigned char buf[128];
+       HCRYPTPROV hcryptprov = source->sources.file.handle;
+       ssize_t ndesired;
+       unsigned int added;
+
+       if (source->bad)
+               return (0);
+
+       desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
+
+       added = 0;
+       while (desired > 0) {
+               ndesired = ISC_MIN(desired, sizeof(buf));
+               if (!CryptGenRandom(hcryptprov, ndesired, buf)) {
+                       CryptReleaseContext(hcryptprov, 0);
+                       source->bad = ISC_TRUE;
+                       goto out;
+               }
+
+               entropypool_adddata(ent, buf, ndesired, ndesired * 8);
+               added += ndesired * 8;
+               desired -= ndesired;
+       }
+
+ out:
+       return (added);
+}
+
+/*
+ * Poll each source, trying to get data from it to stuff into the entropy
+ * pool.
+ */
+static void
+fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
+       unsigned int added;
+       unsigned int remaining;
+       unsigned int needed;
+       unsigned int nsource;
+       isc_entropysource_t *source;
+       isc_entropysource_t *firstsource;
+
+       REQUIRE(VALID_ENTROPY(ent));
+
+       needed = desired;
+
+       /*
+        * This logic is a little strange, so an explanation is in order.
+        *
+        * If needed is 0, it means we are being asked to "fill to whatever
+        * we think is best."  This means that if we have at least a
+        * partially full pool (say, > 1/4th of the pool) we probably don't
+        * need to add anything.
+        *
+        * Also, we will check to see if the "pseudo" count is too high.
+        * If it is, try to mix in better data.  Too high is currently
+        * defined as 1/4th of the pool.
+        *
+        * Next, if we are asked to add a specific bit of entropy, make
+        * certain that we will do so.  Clamp how much we try to add to
+        * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
+        *
+        * Note that if we are in a blocking mode, we will only try to
+        * get as much data as we need, not as much as we might want
+        * to build up.
+        */
+       if (needed == 0) {
+               REQUIRE(!blocking);
+
+               if ((ent->pool.entropy >= RND_POOLBITS / 4)
+                   && (ent->pool.pseudo <= RND_POOLBITS / 4))
+                       return;
+
+               needed = THRESHOLD_BITS * 4;
+       } else {
+               needed = ISC_MAX(needed, THRESHOLD_BITS);
+               needed = ISC_MIN(needed, RND_POOLBITS);
+       }
+
+       /*
+        * In any case, clamp how much we need to how much we can add.
+        */
+       needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
+
+       /*
+        * But wait!  If we're not yet initialized, we need at least
+        *      THRESHOLD_BITS
+        * of randomness.
+        */
+       if (ent->initialized < THRESHOLD_BITS)
+               needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
+
+       /*
+        * Poll each file source to see if we can read anything useful from
+        * it.  XXXMLG When where are multiple sources, we should keep a
+        * record of which one we last used so we can start from it (or the
+        * next one) to avoid letting some sources build up entropy while
+        * others are always drained.
+        */
+
+       added = 0;
+       remaining = needed;
+       if (ent->nextsource == NULL) {
+               ent->nextsource = ISC_LIST_HEAD(ent->sources);
+               if (ent->nextsource == NULL)
+                       return;
+       }
+       source = ent->nextsource;
+       /*
+        * Remember the first source so we can break if we have looped back to
+        * the beginning and still have nothing
+        */
+       firstsource = source;
+ again_file:
+       for (nsource = 0; nsource < ent->nsources; nsource++) {
+               unsigned int got;
+
+               if (remaining == 0)
+                       break;
+
+               got = 0;
+
+               if (source->type == ENTROPY_SOURCETYPE_FILE)
+                       got = get_from_filesource(source, remaining);
+
+               added += got;
+
+               remaining -= ISC_MIN(remaining, got);
+
+               source = ISC_LIST_NEXT(source, link);
+               if (source == NULL)
+                       source = ISC_LIST_HEAD(ent->sources);
+       }
+       ent->nextsource = source;
+
+       /*
+        * Go again only if there's been progress and we've not
+        * gone back to the beginning
+        */
+       if (!(ent->nextsource == firstsource && added == 0)) {
+               if (blocking && remaining != 0) {
+                               goto again_file;
+               }
+       }
+
+       /*
+        * Here, if there are bits remaining to be had and we can block,
+        * check to see if we have a callback source.  If so, call them.
+        */
+       source = ISC_LIST_HEAD(ent->sources);
+       while ((remaining != 0) && (source != NULL)) {
+               unsigned int got;
+
+               got = 0;
+
+               if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
+                       got = get_from_callback(source, remaining, blocking);
+
+               added += got;
+               remaining -= ISC_MIN(remaining, got);
+
+               if (added >= needed)
+                       break;
+
+               source = ISC_LIST_NEXT(source, link);
+       }
+
+       /*
+        * Mark as initialized if we've added enough data.
+        */
+       if (ent->initialized < THRESHOLD_BITS)
+               ent->initialized += added;
+}
+
+
+
+/*
+ * Requires "ent" be locked.
+ */
+static void
+destroyfilesource(isc_entropyfilesource_t *source) {
+       CryptReleaseContext(source->handle, 0);
+}
+
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source) {
+       UNUSED(source);
+}
+
+
+isc_result_t
+isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
+       isc_result_t ret;
+       isc_entropysource_t *source;
+       HCRYPTPROV hcryptprov;
+       DWORD errval;
+       BOOL err;
+
+       REQUIRE(VALID_ENTROPY(ent));
+       REQUIRE(fname != NULL);
+
+       LOCK(&ent->lock);
+
+       source = NULL;
+
+       /*
+        * The first time we just try to acquire the context
+        */
+       err = CryptAcquireContext(&hcryptprov, NULL, NULL, PROV_RSA_FULL,
+                                 CRYPT_VERIFYCONTEXT);
+       if (!err){
+               errval = GetLastError();
+               ret = ISC_R_IOERROR;
+               goto errout;
+       }
+
+       source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
+       if (source == NULL) {
+               ret = ISC_R_NOMEMORY;
+               goto closecontext;
+       }
+
+       /*
+        * From here down, no failures can occur.
+        */
+       source->magic = SOURCE_MAGIC;
+       source->type = ENTROPY_SOURCETYPE_FILE;
+       source->ent = ent;
+       source->total = 0;
+       source->bad = ISC_FALSE;
+       memset(source->name, 0, sizeof(source->name));
+       ISC_LINK_INIT(source, link);
+       source->sources.file.handle = hcryptprov;
+
+       /*
+        * Hook it into the entropy system.
+        */
+       ISC_LIST_APPEND(ent->sources, source, link);
+       ent->nsources++;
+
+       UNLOCK(&ent->lock);
+       return (ISC_R_SUCCESS);
+
+ closecontext:
+       CryptReleaseContext(hcryptprov, 0);
+
+ errout:
+       if (source != NULL)
+               isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
+
+       UNLOCK(&ent->lock);
+
+       return (ret);
+}
+
+
+
+
diff --git a/lib/isc/win32/errno2result.c b/lib/isc/win32/errno2result.c
new file mode 100644 (file)
index 0000000..c3d54d6
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: errno2result.c,v 1.17 2008/09/12 04:46:25 marka Exp $ */
+
+#include <config.h>
+
+#include <winsock2.h>
+#include "errno2result.h"
+#include <isc/result.h>
+#include <isc/strerror.h>
+#include <isc/util.h>
+
+/*
+ * Convert a POSIX errno value into an isc_result_t.  The
+ * list of supported errno values is not complete; new users
+ * of this function should add any expected errors that are
+ * not already there.
+ */
+isc_result_t
+isc__errno2resultx(int posixerrno, const char *file, int line) {
+       char strbuf[ISC_STRERRORSIZE];
+
+       switch (posixerrno) {
+       case ENOTDIR:
+       case WSAELOOP:
+       case WSAEINVAL:
+       case EINVAL:            /* XXX sometimes this is not for files */
+       case ENAMETOOLONG:
+       case WSAENAMETOOLONG:
+       case EBADF:
+       case WSAEBADF:
+               return (ISC_R_INVALIDFILE);
+       case ENOENT:
+               return (ISC_R_FILENOTFOUND);
+       case EACCES:
+       case WSAEACCES:
+       case EPERM:
+               return (ISC_R_NOPERM);
+       case EEXIST:
+               return (ISC_R_FILEEXISTS);
+       case EIO:
+               return (ISC_R_IOERROR);
+       case ENOMEM:
+               return (ISC_R_NOMEMORY);
+       case ENFILE:
+       case EMFILE:
+       case WSAEMFILE:
+               return (ISC_R_TOOMANYOPENFILES);
+       case ERROR_CANCELLED:
+               return (ISC_R_CANCELED);
+       case ERROR_CONNECTION_REFUSED:
+       case WSAECONNREFUSED:
+               return (ISC_R_CONNREFUSED);
+       case WSAENOTCONN:
+       case ERROR_CONNECTION_INVALID:
+               return (ISC_R_NOTCONNECTED);
+       case ERROR_HOST_UNREACHABLE:
+       case WSAEHOSTUNREACH:
+               return (ISC_R_HOSTUNREACH);
+       case ERROR_NETWORK_UNREACHABLE:
+       case WSAENETUNREACH:
+               return (ISC_R_NETUNREACH);
+       case ERROR_NO_NETWORK:
+               return (ISC_R_NETUNREACH);
+       case ERROR_PORT_UNREACHABLE:
+               return (ISC_R_HOSTUNREACH);
+       case ERROR_SEM_TIMEOUT:
+               return (ISC_R_TIMEDOUT);
+       case WSAECONNRESET:
+       case WSAENETRESET:
+       case WSAECONNABORTED:
+       case WSAEDISCON:
+       case ERROR_OPERATION_ABORTED:
+       case ERROR_CONNECTION_ABORTED:
+       case ERROR_REQUEST_ABORTED:
+               return (ISC_R_CONNECTIONRESET);
+       case WSAEADDRNOTAVAIL:
+               return (ISC_R_ADDRNOTAVAIL);
+       case ERROR_NETNAME_DELETED:
+       case WSAENETDOWN:
+               return (ISC_R_NETUNREACH);
+       case WSAEHOSTDOWN:
+               return (ISC_R_HOSTUNREACH);
+       case WSAENOBUFS:
+               return (ISC_R_NORESOURCES);
+       default:
+               isc__strerror(posixerrno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(file, line, "unable to convert errno "
+                                "to isc_result: %d: %s", posixerrno, strbuf);
+               /*
+                * XXXDCL would be nice if perhaps this function could
+                * return the system's error string, so the caller
+                * might have something more descriptive than "unexpected
+                * error" to log with.
+                */
+               return (ISC_R_UNEXPECTED);
+       }
+}
diff --git a/lib/isc/win32/errno2result.h b/lib/isc/win32/errno2result.h
new file mode 100644 (file)
index 0000000..41682db
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: errno2result.h,v 1.10 2007/06/19 23:47:19 tbox Exp $ */
+
+#ifndef UNIX_ERRNO2RESULT_H
+#define UNIX_ERRNO2RESULT_H 1
+
+/* XXXDCL this should be moved to lib/isc/include/isc/errno2result.h. */
+
+#include <errno.h>             /* Provides errno. */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define isc__errno2result(posixerrno) \
+       isc__errno2resultx(posixerrno, __FILE__, __LINE__)
+
+isc_result_t
+isc__errno2resultx(int posixerrno, const char *file, int line);
+
+ISC_LANG_ENDDECLS
+
+#endif /* UNIX_ERRNO2RESULT_H */
diff --git a/lib/isc/win32/file.c b/lib/isc/win32/file.c
new file mode 100644 (file)
index 0000000..baf7953
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: file.c,v 1.31 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <config.h>
+
+#undef rename
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <io.h>
+#include <process.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/utime.h>
+
+#include <isc/file.h>
+#include <isc/result.h>
+#include <isc/time.h>
+#include <isc/util.h>
+#include <isc/stat.h>
+
+#include "errno2result.h"
+
+/*
+ * Emulate UNIX mkstemp, which returns an open FD to the new file
+ *
+ */
+static int
+gettemp(char *path, int *doopen) {
+       char *start, *trv;
+       struct stat sbuf;
+       int pid;
+
+       trv = strrchr(path, 'X');
+       trv++;
+       pid = getpid();
+       /* extra X's get set to 0's */
+       while (*--trv == 'X') {
+               *trv = (pid % 10) + '0';
+               pid /= 10;
+       }
+       /*
+        * check the target directory; if you have six X's and it
+        * doesn't exist this runs for a *very* long time.
+        */
+       for (start = trv + 1;; --trv) {
+               if (trv <= path)
+                       break;
+               if (*trv == '\\') {
+                       *trv = '\0';
+                       if (stat(path, &sbuf))
+                               return (0);
+                       if (!S_ISDIR(sbuf.st_mode)) {
+                               errno = ENOTDIR;
+                               return (0);
+                       }
+                       *trv = '\\';
+                       break;
+               }
+       }
+
+       for (;;) {
+               if (doopen) {
+                       if ((*doopen =
+                           open(path, O_CREAT|O_EXCL|O_RDWR,
+                                _S_IREAD | _S_IWRITE)) >= 0)
+                               return (1);
+                       if (errno != EEXIST)
+                               return (0);
+               } else if (stat(path, &sbuf))
+                       return (errno == ENOENT ? 1 : 0);
+
+               /* tricky little algorithm for backward compatibility */
+               for (trv = start;;) {
+                       if (!*trv)
+                               return (0);
+                       if (*trv == 'z')
+                               *trv++ = 'a';
+                       else {
+                               if (isdigit(*trv))
+                                       *trv = 'a';
+                               else
+                                       ++*trv;
+                               break;
+                       }
+               }
+       }
+       /*NOTREACHED*/
+}
+
+static int
+mkstemp(char *path) {
+       int fd;
+
+       return (gettemp(path, &fd) ? fd : -1);
+}
+
+/*
+ * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
+ * it might be good to provide a mechanism that allows for the results
+ * of a previous stat() to be used again without having to do another stat,
+ * such as perl's mechanism of using "_" in place of a file name to indicate
+ * that the results of the last stat should be used.  But then you get into
+ * annoying MP issues.   BTW, Win32 has stat().
+ */
+static isc_result_t
+file_stats(const char *file, struct stat *stats) {
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(file != NULL);
+       REQUIRE(stats != NULL);
+
+       if (stat(file, stats) != 0)
+               result = isc__errno2result(errno);
+
+       return (result);
+}
+
+/*
+ * isc_file_safemovefile is needed to be defined here to ensure that
+ * any file with the new name is renamed to a backup name and then the
+ * rename is done. If all goes well then the backup can be deleted,
+ * otherwise it gets renamed back.
+ */
+
+int
+isc_file_safemovefile(const char *oldname, const char *newname) {
+       BOOL filestatus;
+       char buf[512];
+       struct stat sbuf;
+       BOOL exists = FALSE;
+       int tmpfd;
+
+       /*
+        * Make sure we have something to do
+        */
+       if (stat(oldname, &sbuf) != 0) {
+               errno = ENOENT;
+               return (-1);
+       }
+
+       /*
+        * Rename to a backup the new file if it still exists
+        */
+       if (stat(newname, &sbuf) == 0) {
+               exists = TRUE;
+               strcpy(buf, newname);
+               strcat(buf, ".XXXXX");
+               tmpfd = mkstemp(buf);
+               if (tmpfd > 0)
+                       _close(tmpfd);
+               DeleteFile(buf);
+               _chmod(newname, _S_IREAD | _S_IWRITE);
+
+               filestatus = MoveFile(newname, buf);
+       }
+       /* Now rename the file to the new name
+        */
+       _chmod(oldname, _S_IREAD | _S_IWRITE);
+
+       filestatus = MoveFile(oldname, newname);
+       if (filestatus == 0) {
+               /*
+                * Try to rename the backup back to the original name
+                * if the backup got created
+                */
+               if (exists == TRUE) {
+                       filestatus = MoveFile(buf, newname);
+                       if (filestatus == 0)
+                               errno = EACCES;
+               }
+               return (-1);
+       }
+
+       /*
+        * Delete the backup file if it got created
+        */
+       if (exists == TRUE)
+               filestatus = DeleteFile(buf);
+       return (0);
+}
+
+isc_result_t
+isc_file_getmodtime(const char *file, isc_time_t *time) {
+       int fh;
+
+       REQUIRE(file != NULL);
+       REQUIRE(time != NULL);
+
+       if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0)
+               return (isc__errno2result(errno));
+
+       if (!GetFileTime((HANDLE) _get_osfhandle(fh),
+                        NULL,
+                        NULL,
+                        &time->absolute))
+       {
+               close(fh);
+                errno = EINVAL;
+                return (isc__errno2result(errno));
+        }
+       close(fh);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_settime(const char *file, isc_time_t *time) {
+       int fh;
+
+       REQUIRE(file != NULL && time != NULL);
+
+       if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0)
+               return (isc__errno2result(errno));
+
+        /*
+        * Set the date via the filedate system call and return.  Failing
+         * this call implies the new file times are not supported by the
+         * underlying file system.
+         */
+       if (!SetFileTime((HANDLE) _get_osfhandle(fh),
+                        NULL,
+                        &time->absolute,
+                        &time->absolute))
+       {
+               close(fh);
+                errno = EINVAL;
+                return (isc__errno2result(errno));
+        }
+
+       close(fh);
+        return (ISC_R_SUCCESS);
+
+}
+
+#undef TEMPLATE
+#define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */
+
+isc_result_t
+isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
+       return (isc_file_template(path, TEMPLATE, buf, buflen));
+}
+
+isc_result_t
+isc_file_template(const char *path, const char *templet, char *buf,
+                       size_t buflen) {
+       char *s;
+
+       REQUIRE(path != NULL);
+       REQUIRE(templet != NULL);
+       REQUIRE(buf != NULL);
+
+       s = strrchr(templet, '\\');
+       if (s != NULL)
+               templet = s + 1;
+
+       s = strrchr(path, '\\');
+
+       if (s != NULL) {
+               if ((s - path + 1 + strlen(templet) + 1) > buflen)
+                       return (ISC_R_NOSPACE);
+
+               strncpy(buf, path, s - path + 1);
+               buf[s - path + 1] = '\0';
+               strcat(buf, templet);
+       } else {
+               if ((strlen(templet) + 1) > buflen)
+                       return (ISC_R_NOSPACE);
+
+               strcpy(buf, templet);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_renameunique(const char *file, char *templet) {
+       int fd = -1;
+       int res = 0;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(file != NULL);
+       REQUIRE(templet != NULL);
+
+       fd = mkstemp(templet);
+       if (fd == -1)
+               result = isc__errno2result(errno);
+       else
+               close(fd);
+
+       if (result == ISC_R_SUCCESS) {
+               res = isc_file_safemovefile(file, templet);
+               if (res != 0) {
+                       result = isc__errno2result(errno);
+                       (void)unlink(templet);
+               }
+       }
+       return (result);
+}
+
+isc_result_t
+isc_file_openunique(char *templet, FILE **fp) {
+       int fd;
+       FILE *f;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(templet != NULL);
+       REQUIRE(fp != NULL && *fp == NULL);
+
+       /*
+        * Win32 does not have mkstemp. Using emulation above.
+        */
+       fd = mkstemp(templet);
+
+       if (fd == -1)
+               result = isc__errno2result(errno);
+       if (result == ISC_R_SUCCESS) {
+               f = fdopen(fd, "w+");
+               if (f == NULL) {
+                       result = isc__errno2result(errno);
+                       (void)remove(templet);
+                       (void)close(fd);
+               } else
+                       *fp = f;
+       }
+
+       return (result);
+}
+
+isc_result_t
+isc_file_remove(const char *filename) {
+       int r;
+
+       REQUIRE(filename != NULL);
+
+       r = unlink(filename);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_file_rename(const char *oldname, const char *newname) {
+       int r;
+
+       REQUIRE(oldname != NULL);
+       REQUIRE(newname != NULL);
+
+       r = isc_file_safemovefile(oldname, newname);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_boolean_t
+isc_file_exists(const char *pathname) {
+       struct stat stats;
+
+       REQUIRE(pathname != NULL);
+
+       return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
+}
+
+isc_boolean_t
+isc_file_isabsolute(const char *filename) {
+       REQUIRE(filename != NULL);
+       /*
+        * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
+        * the UNC style file specs
+        */
+       if ((filename[0] == '\\') && (filename[1] == '\\'))
+               return (ISC_TRUE);
+       if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\')
+               return (ISC_TRUE);
+       if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/')
+               return (ISC_TRUE);
+       return (ISC_FALSE);
+}
+
+isc_boolean_t
+isc_file_iscurrentdir(const char *filename) {
+       REQUIRE(filename != NULL);
+       return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
+}
+
+isc_boolean_t
+isc_file_ischdiridempotent(const char *filename) {
+       REQUIRE(filename != NULL);
+
+       if (isc_file_isabsolute(filename))
+               return (ISC_TRUE);
+       if (filename[0] == '\\')
+               return (ISC_TRUE);
+       if (filename[0] == '/')
+               return (ISC_TRUE);
+       if (isc_file_iscurrentdir(filename))
+               return (ISC_TRUE);
+       return (ISC_FALSE);
+}
+
+const char *
+isc_file_basename(const char *filename) {
+       char *s;
+
+       REQUIRE(filename != NULL);
+
+       s = strrchr(filename, '\\');
+       if (s == NULL)
+               return (filename);
+       return (s + 1);
+}
+
+isc_result_t
+isc_file_progname(const char *filename, char *progname, size_t namelen) {
+       const char *s;
+       char *p;
+       size_t len;
+
+       REQUIRE(filename != NULL);
+       REQUIRE(progname != NULL);
+
+       /*
+        * Strip the path from the name
+        */
+       s = isc_file_basename(filename);
+       if (s == NULL) {
+               return (ISC_R_NOSPACE);
+       }
+
+       /*
+        * Strip any and all suffixes
+        */
+       p = strchr(s, '.');
+       if (p == NULL) {
+               if (namelen <= strlen(s))
+                       return (ISC_R_NOSPACE);
+
+               strcpy(progname, s);
+               return (ISC_R_SUCCESS);
+       }
+
+       /* 
+        * Copy the result to the buffer
+        */
+       len = p - s;
+       if (len >= namelen)
+               return (ISC_R_NOSPACE);
+
+       strncpy(progname, s, len);
+       progname[len] = '\0';
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
+       char *ptrname;
+       DWORD retval;
+
+       REQUIRE(filename != NULL);
+       REQUIRE(path != NULL);
+
+       retval = GetFullPathName(filename, pathlen, path, &ptrname);
+
+       /* Something went wrong in getting the path */
+       if (retval == 0)
+               return (ISC_R_NOTFOUND);
+       /* Caller needs to provide a larger buffer to contain the string */
+       if (retval >= pathlen)
+               return (ISC_R_NOSPACE);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_truncate(const char *filename, isc_offset_t size) {
+       int fh;
+
+       REQUIRE(filename != NULL && size >= 0);
+
+       if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0)
+               return (isc__errno2result(errno));
+
+       if(_chsize(fh, size) != 0) {
+               close(fh);
+               return (isc__errno2result(errno));
+       }
+       close(fh);
+
+       return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/win32/fsaccess.c b/lib/isc/win32/fsaccess.c
new file mode 100644 (file)
index 0000000..8de793f
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: fsaccess.c,v 1.15 2007/06/19 23:47:19 tbox Exp $ */
+
+/*
+ * Note that Win32 does not have the concept of files having access
+ * and ownership bits.  The FAT File system only has a readonly flag
+ * for everyone and that's all. NTFS uses ACL's which is a totally
+ * different concept of controlling access.
+ *
+ * This code needs to be revisited to set up proper access control for
+ * NTFS file systems.  Nothing can be done for FAT file systems.
+ */
+
+#include <config.h>
+
+#include <aclapi.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+#include <errno.h>
+
+#include <isc/file.h>
+#include <isc/stat.h>
+
+#include "errno2result.h"
+
+/*
+ * The OS-independent part of the API is in lib/isc.
+ */
+#include "../fsaccess.c"
+
+/* Store the user account name locally */
+static char username[255] = "\0";
+static DWORD namelen = 0;
+
+/*
+ * In order to set or retrieve access information, we need to obtain
+ * the File System type.  These could be UNC-type shares.
+ */
+
+BOOL
+is_ntfs(const char * file) {
+
+       char drive[255];
+       char FSType[20];
+       char tmpbuf[256];
+       char *machinename;
+       char *sharename;
+       char filename[1024];
+
+       REQUIRE(filename != NULL);
+
+       if (isc_file_absolutepath(file, filename,
+               sizeof(filename)) != ISC_R_SUCCESS) {
+               return (FALSE);
+       }
+
+       /*
+        * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
+        * the UNC style file specs
+        */
+       if (isalpha(filename[0]) && filename[1] == ':' && 
+               (filename[2] == '\\' || filename[2] == '/')) {
+               strncpy(drive, filename, 3);
+               drive[3] = '\0';
+       }
+
+       else if ((filename[0] == '\\') && (filename[1] == '\\')) {
+               /* Find the machine and share name and rebuild the UNC */
+               strcpy(tmpbuf, filename);
+               machinename = strtok(tmpbuf, "\\");
+               sharename = strtok(NULL, "\\");
+               strcpy(drive, "\\\\");
+               strcat(drive, machinename);
+               strcat(drive, "\\");
+               strcat(drive, sharename);
+               strcat(drive, "\\");
+
+       }
+       else /* Not determinable */
+               return (FALSE);
+               
+       GetVolumeInformation(drive, NULL, 0, NULL, 0, NULL, FSType,
+                            sizeof(FSType));
+       if(strcmp(FSType,"NTFS") == 0)
+               return (TRUE);
+       else
+               return (FALSE);
+}
+
+/*
+ * If it's not NTFS, we assume that it is FAT and proceed
+ * with almost nothing to do. Only the write flag can be set or
+ * cleared.
+ */
+isc_result_t
+FAT_fsaccess_set(const char *path, isc_fsaccess_t access) {
+       int mode;
+       isc_fsaccess_t bits;
+
+       /*
+        * Done with checking bad bits.  Set mode_t.
+        */
+       mode = 0;
+
+#define SET_AND_CLEAR1(modebit) \
+       if ((access & bits) != 0) { \
+               mode |= modebit; \
+               access &= ~bits; \
+       }
+#define SET_AND_CLEAR(user, group, other) \
+       SET_AND_CLEAR1(user); \
+       bits <<= STEP; \
+       SET_AND_CLEAR1(group); \
+       bits <<= STEP; \
+       SET_AND_CLEAR1(other);
+
+       bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY;
+
+       SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH);
+
+       bits = ISC_FSACCESS_WRITE |
+              ISC_FSACCESS_CREATECHILD |
+              ISC_FSACCESS_DELETECHILD;
+
+       SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH);
+
+       INSIST(access == 0);
+
+       if (_chmod(path, mode) < 0)
+               return (isc__errno2result(errno));
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+NTFS_Access_Control(const char *filename, const char *user, int access,
+                   isc_boolean_t isdir) {
+       SECURITY_DESCRIPTOR sd;
+       BYTE aclBuffer[1024];
+       PACL pacl=(PACL)&aclBuffer;
+       BYTE sidBuffer[100];
+       PSID psid=(PSID) &sidBuffer;
+       DWORD sidBufferSize = sizeof(sidBuffer);
+       BYTE adminSidBuffer[100];
+       PSID padminsid=(PSID) &adminSidBuffer;
+       DWORD adminSidBufferSize = sizeof(adminSidBuffer);
+       BYTE otherSidBuffer[100];
+       PSID pothersid=(PSID) &otherSidBuffer;
+       DWORD otherSidBufferSize = sizeof(otherSidBuffer);
+       char domainBuffer[100];
+       DWORD domainBufferSize = sizeof(domainBuffer);
+       SID_NAME_USE snu;
+       int errval;
+       DWORD NTFSbits;
+       int caccess;
+
+
+       /* Initialize an ACL */
+       if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
+               return (ISC_R_NOPERM);
+       if (!InitializeAcl(pacl, sizeof(aclBuffer), ACL_REVISION))
+               return (ISC_R_NOPERM);
+       if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer,
+                         &domainBufferSize, &snu))
+               return (ISC_R_NOPERM);
+       domainBufferSize = sizeof(domainBuffer);
+       if (!LookupAccountName(0, "Administrators", padminsid,
+               &adminSidBufferSize, domainBuffer, &domainBufferSize, &snu)) {
+               errval = GetLastError();
+               return (ISC_R_NOPERM);
+       }
+       domainBufferSize = sizeof(domainBuffer);
+       if (!LookupAccountName(0, "Everyone", pothersid,
+               &otherSidBufferSize, domainBuffer, &domainBufferSize, &snu)) {
+               errval = GetLastError();
+               return (ISC_R_NOPERM);
+       }
+
+       caccess = access;
+       /* Owner check */
+
+       NTFSbits = 0;
+       if (caccess & ISC_FSACCESS_READ)
+               NTFSbits |= FILE_GENERIC_READ;
+       if (caccess & ISC_FSACCESS_WRITE)
+               NTFSbits |= FILE_GENERIC_WRITE;
+       if (caccess & ISC_FSACCESS_EXECUTE)
+               NTFSbits |= FILE_GENERIC_EXECUTE;
+
+       /* For directories check the directory-specific bits */
+       if (isdir == ISC_TRUE) {
+               if (caccess & ISC_FSACCESS_CREATECHILD)
+                       NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE;
+               if (caccess & ISC_FSACCESS_DELETECHILD)
+                       NTFSbits |= FILE_DELETE_CHILD;
+               if (caccess & ISC_FSACCESS_LISTDIRECTORY)
+                       NTFSbits |= FILE_LIST_DIRECTORY;
+               if (caccess & ISC_FSACCESS_ACCESSCHILD)
+                       NTFSbits |= FILE_TRAVERSE;
+       }
+
+       if (NTFSbits == (FILE_GENERIC_READ | FILE_GENERIC_WRITE
+                    | FILE_GENERIC_EXECUTE))
+                    NTFSbits |= FILE_ALL_ACCESS;
+       /*
+        * Owner and Administrator also get STANDARD_RIGHTS_ALL
+        * to ensure that they have full control
+        */
+
+       NTFSbits |= STANDARD_RIGHTS_ALL;
+
+       /* Add the ACE to the ACL */
+       if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, psid))
+               return (ISC_R_NOPERM);
+       if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, padminsid))
+               return (ISC_R_NOPERM);
+
+       /*
+        * Group is ignored since we can be in multiple groups or no group
+        * and its meaning is not clear on Win32
+        */
+
+       caccess = caccess >> STEP;
+
+       /*
+        * Other check.  We translate this to be the same as Everyone
+        */
+
+       caccess = caccess >> STEP;
+
+       NTFSbits = 0;
+       if (caccess & ISC_FSACCESS_READ)
+               NTFSbits |= FILE_GENERIC_READ;
+       if (caccess & ISC_FSACCESS_WRITE)
+               NTFSbits |= FILE_GENERIC_WRITE;
+       if (caccess & ISC_FSACCESS_EXECUTE)
+               NTFSbits |= FILE_GENERIC_EXECUTE;
+
+       /* For directories check the directory-specific bits */
+       if (isdir == TRUE) {
+               if (caccess & ISC_FSACCESS_CREATECHILD)
+                       NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE;
+               if (caccess & ISC_FSACCESS_DELETECHILD)
+                       NTFSbits |= FILE_DELETE_CHILD;
+               if (caccess & ISC_FSACCESS_LISTDIRECTORY)
+                       NTFSbits |= FILE_LIST_DIRECTORY;
+               if (caccess & ISC_FSACCESS_ACCESSCHILD)
+                       NTFSbits |= FILE_TRAVERSE;
+       }
+       /* Add the ACE to the ACL */
+       if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits,
+                                pothersid))
+               return (ISC_R_NOPERM);
+
+       if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE))
+               return (ISC_R_NOPERM);
+       if (!SetFileSecurity(filename, DACL_SECURITY_INFORMATION, &sd)) {
+               return (ISC_R_NOPERM);
+       }
+
+       return(ISC_R_SUCCESS);
+}
+
+isc_result_t
+NTFS_fsaccess_set(const char *path, isc_fsaccess_t access,
+                 isc_boolean_t isdir){
+
+       /*
+        * For NTFS we first need to get the name of the account under
+        * which BIND is running
+        */
+       if (namelen <= 0) {
+               namelen = sizeof(username);
+               if (GetUserName(username, &namelen) == 0)
+                       return (ISC_R_FAILURE);
+       }
+       return (NTFS_Access_Control(path, username, access, isdir));
+}
+
+isc_result_t
+isc_fsaccess_set(const char *path, isc_fsaccess_t access) {
+       struct stat statb;
+       isc_boolean_t is_dir = ISC_FALSE;
+       isc_result_t result;
+
+       if (stat(path, &statb) != 0)
+               return (isc__errno2result(errno));
+
+       if ((statb.st_mode & S_IFDIR) != 0)
+               is_dir = ISC_TRUE;
+       else if ((statb.st_mode & S_IFREG) == 0)
+               return (ISC_R_INVALIDFILE);
+
+       result = check_bad_bits(access, is_dir);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       /*
+        * Determine if this is a FAT or NTFS disk and
+        * call the appropriate function to set the permissions
+        */
+       if (is_ntfs(path))
+               return (NTFS_fsaccess_set(path, access, is_dir));
+       else
+               return (FAT_fsaccess_set(path, access));
+}
+
+isc_result_t
+isc_fsaccess_changeowner(const char *filename, const char *user) {
+       SECURITY_DESCRIPTOR psd;
+       BYTE sidBuffer[500];
+       BYTE groupBuffer[500];
+       PSID psid=(PSID) &sidBuffer;
+       DWORD sidBufferSize = sizeof(sidBuffer);
+       char domainBuffer[100];
+       DWORD domainBufferSize = sizeof(domainBuffer);
+       SID_NAME_USE snu;
+       PSID pSidGroup = (PSID) &groupBuffer;
+       DWORD groupBufferSize = sizeof(groupBuffer);
+
+
+       /*
+        * Determine if this is a FAT or NTFS disk and
+        * call the appropriate function to set the ownership
+        * FAT disks do not have ownership attributes so it's
+        * a noop.
+        */
+       if (is_ntfs(filename) == FALSE)
+               return (ISC_R_SUCCESS);
+
+       if (!InitializeSecurityDescriptor(&psd, SECURITY_DESCRIPTOR_REVISION))
+               return (ISC_R_NOPERM);
+
+       if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer,
+               &domainBufferSize, &snu))
+               return (ISC_R_NOPERM);
+
+       /* Make sure administrators can get to it */
+       domainBufferSize = sizeof(domainBuffer);
+       if (!LookupAccountName(0, "Administrators", pSidGroup,
+               &groupBufferSize, domainBuffer, &domainBufferSize, &snu))
+               return (ISC_R_NOPERM);
+
+       if (!SetSecurityDescriptorOwner(&psd, psid, FALSE))
+               return (ISC_R_NOPERM);
+
+       if (!SetSecurityDescriptorGroup(&psd, pSidGroup, FALSE))
+               return (ISC_R_NOPERM);
+
+       if (!SetFileSecurity(filename,
+               OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
+               &psd))
+               return (ISC_R_NOPERM);
+
+       return (ISC_R_SUCCESS);
+}
+
diff --git a/lib/isc/win32/include/isc/bind_registry.h b/lib/isc/win32/include/isc/bind_registry.h
new file mode 100644 (file)
index 0000000..c4dc876
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: bind_registry.h,v 1.8 2007/06/19 23:47:20 tbox Exp $ */
+
+#ifndef ISC_BINDREGISTRY_H
+#define ISC_BINDREGISTRY_H
+
+/*
+ * BIND makes use of the following Registry keys in various places, especially
+ * during startup and installation
+ */
+
+#define BIND_SUBKEY            "Software\\ISC\\BIND"
+#define BIND_SESSION           "CurrentSession"
+#define BIND_SESSION_SUBKEY    "Software\\ISC\\BIND\\CurrentSession"
+#define BIND_UNINSTALL_SUBKEY  \
+       "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ISC BIND"
+
+#define EVENTLOG_APP_SUBKEY    \
+       "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"
+#define BIND_MESSAGE_SUBKEY    \
+       "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\named"
+#define BIND_MESSAGE_NAME      "named"
+
+#define BIND_SERVICE_SUBKEY    \
+       "SYSTEM\\CurrentControlSet\\Services\\named"
+
+
+#define BIND_CONFIGFILE                0
+#define BIND_DEBUGLEVEL                1
+#define BIND_QUERYLOG          2
+#define BIND_FOREGROUND                3
+#define BIND_PORT              4
+
+#endif /* ISC_BINDREGISTRY_H */
diff --git a/lib/isc/win32/include/isc/bindevt.h b/lib/isc/win32/include/isc/bindevt.h
new file mode 100644 (file)
index 0000000..72cf2d1
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: bindevt.h,v 1.6 2007/06/19 23:47:20 tbox Exp $ */
+
+#ifndef ISC_BINDEVT_H
+#define ISC_BINDEVT_H 1
+
+/*
+ * This is used for the event log for both logging the messages and
+ * later on by the event viewer when looking at the events
+ */
+
+/*
+ * Values are 32 bit values layed out as follows:
+ *
+ *   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ *  +---+-+-+-----------------------+-------------------------------+
+ *  |Sev|C|R|     Facility          |               Code            |
+ *  +---+-+-+-----------------------+-------------------------------+
+ *
+ *  where
+ *
+ *      Sev - is the severity code
+ *
+ *          00 - Success
+ *          01 - Informational
+ *          10 - Warning
+ *          11 - Error
+ *
+ *      C - is the Customer code flag
+ *
+ *      R - is a reserved bit
+ *
+ *      Facility - is the facility code
+ *
+ *      Code - is the facility's status code
+ *
+ *
+ * Define the facility codes
+ */
+
+/*
+ * Define the severity codes
+ */
+
+
+/*
+ * MessageId: BIND_ERR_MSG
+ *
+ * MessageText:
+ *
+ *  %1
+ */
+#define BIND_ERR_MSG           ((DWORD)0xC0000001L)
+
+/*
+ * MessageId: BIND_WARN_MSG
+ *
+ * MessageText:
+ *
+ *  %1
+ */
+#define BIND_WARN_MSG          ((DWORD)0x80000002L)
+
+/*
+ * MessageId: BIND_INFO_MSG
+ *
+ * MessageText:
+ *
+ *  %1
+ */
+#define BIND_INFO_MSG          ((DWORD)0x40000003L)
+
+#endif /* ISC_BINDEVT_H */
diff --git a/lib/isc/win32/include/isc/condition.h b/lib/isc/win32/include/isc/condition.h
new file mode 100644 (file)
index 0000000..34015bc
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: condition.h,v 1.17 2007/06/18 23:47:49 tbox Exp $ */
+
+#ifndef ISC_CONDITION_H
+#define ISC_CONDITION_H 1
+
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/thread.h>
+#include <isc/types.h>
+
+typedef struct isc_condition_thread isc_condition_thread_t;
+
+struct isc_condition_thread {
+       unsigned long                           th;
+       HANDLE                                  handle[2];
+       ISC_LINK(isc_condition_thread_t)        link;
+
+};
+
+typedef struct isc_condition {
+       HANDLE          events[2];
+       unsigned int    waiters;
+       ISC_LIST(isc_condition_thread_t) threadlist;
+} isc_condition_t;
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_condition_init(isc_condition_t *);
+
+isc_result_t
+isc_condition_wait(isc_condition_t *, isc_mutex_t *);
+
+isc_result_t
+isc_condition_signal(isc_condition_t *);
+
+isc_result_t
+isc_condition_broadcast(isc_condition_t *);
+
+isc_result_t
+isc_condition_destroy(isc_condition_t *);
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_CONDITION_H */
diff --git a/lib/isc/win32/include/isc/dir.h b/lib/isc/win32/include/isc/dir.h
new file mode 100644 (file)
index 0000000..653427a
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dir.h,v 1.15 2007/06/19 23:47:20 tbox Exp $ */
+
+/* Principal Authors: DCL */
+
+#ifndef ISC_DIR_H
+#define ISC_DIR_H 1
+
+#include <windows.h>
+#include <stdlib.h>
+
+#include <isc/lang.h>
+#include <isc/boolean.h>
+#include <isc/result.h>
+
+#define ISC_DIR_NAMEMAX _MAX_FNAME
+#define ISC_DIR_PATHMAX _MAX_PATH
+
+typedef struct {
+       char            name[ISC_DIR_NAMEMAX];
+       unsigned int    length;
+       WIN32_FIND_DATA find_data;
+} isc_direntry_t;
+
+typedef struct {
+       unsigned int    magic;
+       char            dirname[ISC_DIR_PATHMAX];
+       isc_direntry_t  entry;
+       isc_boolean_t   entry_filled;
+       HANDLE          search_handle;
+} isc_dir_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_dir_init(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname);
+
+isc_result_t
+isc_dir_read(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_reset(isc_dir_t *dir);
+
+void
+isc_dir_close(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_chdir(const char *dirname);
+
+isc_result_t
+isc_dir_chroot(const char *dirname);
+
+isc_result_t
+isc_dir_createunique(char *templet);
+/*
+ * Use a templet (such as from isc_file_mktemplate()) to create a uniquely
+ * named, empty directory.  The templet string is modified in place.
+ * If result == ISC_R_SUCCESS, it is the name of the directory that was
+ * created.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_DIR_H */
index 46430c3a8b2acc6d28048a2fb04956b98918b6c6..2ee8bf96a3fb8622763f9b74357721890487bf5d 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: int.h,v 1.10 2001/07/09 21:06:26 gson Exp $ */
+/* $Id: int.h,v 1.13 2007/06/19 23:47:20 tbox Exp $ */
 
 #ifndef ISC_INT_H
 #define ISC_INT_H 1
index 828ca762e57a7c813a5e3b399e99b34112ddbf22..c9add0b37944c44be3c3bf584d1f306fadcea0aa 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
- * Copyright (C) 2000-2002  Internet Software Consortium.
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ipv6.h,v 1.9.2.2.2.5 2004/04/19 06:39:55 marka Exp $ */
+/* $Id: ipv6.h,v 1.19 2007/06/18 23:47:49 tbox Exp $ */
 
 #ifndef ISC_IPV6_H
 #define ISC_IPV6_H 1
@@ -40,7 +40,7 @@
  *     No anticipated impact.
  *
  * Standards:
- *     RFC 2553.
+ *     RFC2553.
  */
 
 #if _MSC_VER < 1300
 #define IN6ADDR_LOOPBACK_INIT  {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}
 #endif
 
-extern const struct in6_addr isc_in6addr_any;
-extern const struct in6_addr isc_in6addr_loopback;
+LIBISC_EXTERNAL_DATA extern const struct in6_addr isc_in6addr_any;
+LIBISC_EXTERNAL_DATA extern const struct in6_addr isc_in6addr_loopback;
 
 /*
  * Unspecified
  */
-
 #ifndef IN6_IS_ADDR_UNSPECIFIED
-#define IN6_IS_ADDR_UNSPECIFIED(a)     (\
+#define IN6_IS_ADDR_UNSPECIFIED(a) (\
 *((u_long *)((a)->s6_addr)    ) == 0 && \
 *((u_long *)((a)->s6_addr) + 1) == 0 && \
 *((u_long *)((a)->s6_addr) + 2) == 0 && \
 *((u_long *)((a)->s6_addr) + 3) == 0 \
 )
 #endif
+
 /*
  * Loopback
  */
@@ -84,7 +84,6 @@ extern const struct in6_addr isc_in6addr_loopback;
 /*
  * IPv4 compatible
  */
-#ifndef IN6_IS_ADDR_V4COMPAT
 #define IN6_IS_ADDR_V4COMPAT(a)  (\
 *((u_long *)((a)->s6_addr)    ) == 0 && \
 *((u_long *)((a)->s6_addr) + 1) == 0 && \
@@ -92,25 +91,21 @@ extern const struct in6_addr isc_in6addr_loopback;
 *((u_long *)((a)->s6_addr) + 3) != 0 && \
 *((u_long *)((a)->s6_addr) + 3) != htonl(1) \
 )
-#endif
 
 /*
  * Mapped
  */
-#ifndef IN6_IS_ADDR_V4MAPPED
 #define IN6_IS_ADDR_V4MAPPED(a) (\
 *((u_long *)((a)->s6_addr)    ) == 0 && \
 *((u_long *)((a)->s6_addr) + 1) == 0 && \
 *((u_long *)((a)->s6_addr) + 2) == htonl(0x0000ffff))
-#endif
 
 /*
  * Multicast
  */
-#ifndef IN6_IS_ADDR_MULTICAST
 #define IN6_IS_ADDR_MULTICAST(a)       \
        ((a)->s6_addr[0] == 0xffU)
-#endif
+
 /*
  * Unicast link / site local.
  */
diff --git a/lib/isc/win32/include/isc/keyboard.h b/lib/isc/win32/include/isc/keyboard.h
new file mode 100644 (file)
index 0000000..e781c5f
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: keyboard.h,v 1.6 2007/06/19 23:47:20 tbox Exp $ */
+
+#ifndef ISC_KEYBOARD_H
+#define ISC_KEYBOARD_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef struct {
+       int fd;
+       isc_result_t result;
+} isc_keyboard_t;
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard);
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleepseconds);
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp);
+
+isc_boolean_t
+isc_keyboard_canceled(isc_keyboard_t *keyboard);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_KEYBOARD_H */
index cb168ac3f037169f1f5516661797eb75511250ab..921c1e9380b1a22bd127f0b45c4a0af8c70e11dd 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: mutex.h,v 1.16 2001/07/09 21:06:27 gson Exp $ */
+/* $Id: mutex.h,v 1.20.56.2 2009/01/18 23:47:41 tbox Exp $ */
 
 #ifndef ISC_MUTEX_H
 #define ISC_MUTEX_H 1
 
 typedef CRITICAL_SECTION isc_mutex_t;
 
-/* This definition is here since WINBASE.H omits it for some reason */
-
+/*
+ * This definition is here since some versions of WINBASE.H
+ * omits it for some reason.
+ */
+#if (_WIN32_WINNT < 0x0400)
 WINBASEAPI BOOL WINAPI
 TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+#endif /* _WIN32_WINNT < 0x0400 */
 
 #define isc_mutex_init(mp) \
        (InitializeCriticalSection((mp)), ISC_R_SUCCESS)
@@ -46,6 +50,6 @@ TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
 /*
  * This is a placeholder for now since we are not keeping any mutex stats
  */
-#define isc_mutex_stats(fp)
+#define isc_mutex_stats(fp) do {} while (0)
 
 #endif /* ISC_MUTEX_H */
diff --git a/lib/isc/win32/include/isc/netdb.h b/lib/isc/win32/include/isc/netdb.h
new file mode 100644 (file)
index 0000000..6625afd
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: netdb.h,v 1.9 2007/06/19 23:47:20 tbox Exp $ */
+
+#ifndef ISC_NETDB_H
+#define ISC_NETDB_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * Portable netdb.h support.
+ *
+ * This module is responsible for defining the get<x>by<y> APIs.
+ *
+ * MP:
+ *     No impact.
+ *
+ * Reliability:
+ *     No anticipated impact.
+ *
+ * Resources:
+ *     N/A.
+ *
+ * Security:
+ *     No anticipated impact.
+ *
+ * Standards:
+ *     BSD API
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/net.h>
+
+#endif /* ISC_NETDB_H */
diff --git a/lib/isc/win32/include/isc/ntgroups.h b/lib/isc/win32/include/isc/ntgroups.h
new file mode 100644 (file)
index 0000000..b4cd020
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ntgroups.h,v 1.5 2007/06/19 23:47:20 tbox Exp $ */
+
+#ifndef ISC_NTGROUPS_H
+#define ISC_NTGROUPS_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+
+isc_result_t
+isc_ntsecurity_getaccountgroups(char *name, char **Groups, unsigned int maxgroups,
+            unsigned int *total);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NTGROUPS_H */
diff --git a/lib/isc/win32/include/isc/ntpaths.h b/lib/isc/win32/include/isc/ntpaths.h
new file mode 100644 (file)
index 0000000..7cd185a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ntpaths.h,v 1.16 2007/06/19 23:47:20 tbox Exp $ */
+
+/*
+ * Windows-specific path definitions
+ * These routines are used to set up and return system-specific path
+ * information about the files enumerated in NtPaths
+ */
+
+#ifndef ISC_NTPATHS_H
+#define ISC_NTPATHS_H
+
+#include <isc/lang.h>
+
+/*
+ * Index of paths needed
+ */
+enum NtPaths {
+       NAMED_CONF_PATH,
+       LWRES_CONF_PATH,
+       RESOLV_CONF_PATH,
+       RNDC_CONF_PATH,
+       NAMED_PID_PATH,
+       LWRESD_PID_PATH,
+       LOCAL_STATE_DIR,
+       SYS_CONF_DIR,
+       RNDC_KEY_PATH
+};
+
+/*
+ * Define macros to get the path of the config files
+ */
+#define NAMED_CONFFILE isc_ntpaths_get(NAMED_CONF_PATH)
+#define RNDC_CONFFILE isc_ntpaths_get(RNDC_CONF_PATH)
+#define RNDC_KEYFILE isc_ntpaths_get(RNDC_KEY_PATH)
+#define RESOLV_CONF isc_ntpaths_get(RESOLV_CONF_PATH)
+
+
+/*
+ * Information about where the files are on disk
+ */
+#define NS_LOCALSTATEDIR       "/dns/bin"
+#define NS_SYSCONFDIR          "/dns/etc"
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_ntpaths_init(void);
+
+char *
+isc_ntpaths_get(int);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NTPATHS_H */
index cd34ffb11e1e16d0990393f3d792d94f3cbac01b..f22fdce0a171856aee703008515eae443335216e 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2000, 2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: offset.h,v 1.2 2001/07/08 05:09:32 mayer Exp $ */
+/* $Id: offset.h,v 1.6 2007/06/19 23:47:20 tbox Exp $ */
 
 #ifndef ISC_OFFSET_H
 #define ISC_OFFSET_H 1
@@ -25,9 +25,8 @@
  */
 #include <limits.h>             /* Required for CHAR_BIT. */
 #include <sys/types.h>
-typedef long off_t;
 
-typedef off_t isc_offset_t;
+typedef _off_t isc_offset_t;
 
 /*
  * POSIX says "Additionally, blkcnt_t and off_t are extended signed integral
index e5e8366aae89f3dcdbbf6fc7b7078fe6749fa1c5..32af1bdf4cb9cfe72623a6b5e734b25f24e1a458 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: once.h,v 1.6 2001/01/09 21:59:06 bwelling Exp $ */
+/* $Id: once.h,v 1.9 2007/06/19 23:47:20 tbox Exp $ */
 
 #ifndef ISC_ONCE_H
 #define ISC_ONCE_H 1
index 10e2a012b81f4698db5ce9d0d3d5223686a40f42..c93b50c7472044b974d037b69f2de18faf536c64 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004, 2005, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: platform.h,v 1.7 2001/11/19 22:32:04 gson Exp $ */
+/* $Id: platform.h,v 1.16.118.2 2009/02/16 23:47:15 tbox Exp $ */
 
 #ifndef ISC_PLATFORM_H
 #define ISC_PLATFORM_H 1
  *** Network.
  ***/
 
-/*
- * This should not be defined yet until we can support IPV6
- * on Windows Platforms.
- *
 #define ISC_PLATFORM_HAVEIPV6
-*/
+#if _MSC_VER > 1200
+#define ISC_PLATFORM_HAVEIN6PKTINFO
+#endif
+#define ISC_PLATFORM_HAVESCOPEID
 #define ISC_PLATFORM_NEEDPORTT
 #undef MSG_TRUNC
 #define ISC_PLATFORM_NEEDNTOP
 #define ISC_PLATFORM_NEEDPTON
-#define ISC_PLATFORM_NEEDATON
 
 #define ISC_PLATFORM_QUADFORMAT "I64"
 
 #define ISC_PLATFORM_NEEDSTRSEP
+#define ISC_PLATFORM_NEEDSTRLCPY
+#define ISC_PLATFORM_NEEDSTRLCAT
+#define ISC_PLATFORM_NEEDSTRLCPY
 
 /*
  * Used to control how extern data is linked; needed for Win32 platforms.
  * and we don't want to redeclare it.
  */
 #define ISC_PLATFORM_NONSTDHERRNO
+
+/*
+ * Define if the platform has <sys/un.h>.
+ */
+#undef ISC_PLATFORM_HAVESYSUNH
+
  /*
  * Set up a macro for importing and exporting from the DLL
  */
 
-#define LIBISC_EXTERNAL_DATA 
-#if 0
 #ifdef LIBISC_EXPORTS
 #define LIBISC_EXTERNAL_DATA __declspec(dllexport)
 #else
-#define LIBISC_EXTERNAL_DATA __declspec(dllimport) 
+#define LIBISC_EXTERNAL_DATA __declspec(dllimport)
 #endif
 
 #ifdef LIBISCCFG_EXPORTS
 #define LIBISCCFG_EXTERNAL_DATA __declspec(dllexport)
 #else
-#define LIBISCCFG_EXTERNAL_DATA __declspec(dllimport) 
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllimport)
 #endif
 
 #ifdef LIBISCCC_EXPORTS
 #define LIBISCCC_EXTERNAL_DATA __declspec(dllexport)
 #else
-#define LIBISCCC_EXTERNAL_DATA __declspec(dllimport) 
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllimport)
 #endif
 
 #ifdef LIBDNS_EXPORTS
@@ -92,6 +97,4 @@
 #define LIBBIND9_EXTERNAL_DATA __declspec(dllimport)
 #endif
 
-#endif /* if 0 */
-
 #endif /* ISC_PLATFORM_H */
index cb67351fd6aab13e873adcfb8ec05b08f0f1732f..2638a916ddc8bb1de295ae08b82127a25304fac8 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: stat.h,v 1.3.2.2.2.1 2004/03/06 08:15:17 marka Exp $ */
+/* $Id: stat.h,v 1.7 2007/06/19 23:47:20 tbox Exp $ */
 
 #ifndef ISC_STAT_H
 #define ISC_STAT_H 1
 
 #include <sys/stat.h>
-#include <fcntl.h>
-#include <io.h>
 
 /* open() under unix allows setting of read/write permissions
  * at the owner, group and other levels.  These don't exist in NT
 # define S_ISREG(m)    (((m) & S_IFMT) == S_IFREG)
 #endif
 
-#define S_IFMT   _S_IFMT         /* file type mask */
-#define S_IFDIR  _S_IFDIR        /* directory */
-#define S_IFCHR  _S_IFCHR        /* character special */
-#define S_IFIFO  _S_IFIFO        /* pipe */
-#define S_IFREG  _S_IFREG        /* regular */
-#define S_IREAD  _S_IREAD        /* read permission, owner */
-#define S_IWRITE _S_IWRITE       /* write permission, owner */
-#define S_IEXEC  _S_IEXEC        /* execute/search permission, owner */
-
-#define O_RDONLY        _O_RDONLY
-#define O_WRONLY        _O_WRONLY
-#define O_RDWR          _O_RDWR
-#define O_APPEND        _O_APPEND
-#define O_CREAT         _O_CREAT
-#define O_TRUNC         _O_TRUNC
-#define O_EXCL          _O_EXCL
-
-
 #endif /* ISC_STAT_H */
diff --git a/lib/isc/win32/include/isc/stdtime.h b/lib/isc/win32/include/isc/stdtime.h
new file mode 100644 (file)
index 0000000..4f9eb74
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stdtime.h,v 1.12 2007/06/19 23:47:20 tbox Exp $ */
+
+#ifndef ISC_STDTIME_H
+#define ISC_STDTIME_H 1
+
+#include <isc/lang.h>
+#include <isc/int.h>
+
+/*
+ * It's public information that 'isc_stdtime_t' is an unsigned integral type.
+ * Applications that want maximum portability should not assume anything
+ * about its size.
+ */
+typedef isc_uint32_t isc_stdtime_t;
+/*
+ * isc_stdtime32_t is a 32-bit version of isc_stdtime_t.  A variable of this
+ * type should only be used as an opaque integer (e.g.,) to compare two
+ * time values.
+ */
+typedef isc_uint32_t isc_stdtime32_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_stdtime_get(isc_stdtime_t *t);
+/*
+ * Set 't' to the number of seconds since 00:00:00 UTC, January 1, 1970.
+ *
+ * Requires:
+ *
+ *     't' is a valid pointer.
+ */
+
+#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
+/*
+ * Convert the standard time to its 32-bit version.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_STDTIME_H */
index 37396816de9b054a123de2176098c7db226e6237..38d2ef2b45e9568d99ad7f089a3e8d03808d4016 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: strerror.h,v 1.2 2001/11/20 01:45:49 gson Exp $ */
+/* $Id: strerror.h,v 1.5 2007/06/19 23:47:20 tbox Exp $ */
 
 #ifndef ISC_STRERROR_H
 #define ISC_STRERROR_H
diff --git a/lib/isc/win32/include/isc/syslog.h b/lib/isc/win32/include/isc/syslog.h
new file mode 100644 (file)
index 0000000..765c0e5
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: syslog.h,v 1.5 2007/06/19 23:47:20 tbox Exp $ */
+
+#ifndef ISC_SYSLOG_H
+#define ISC_SYSLOG_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp);
+/*
+ * Convert 'str' to the appropriate syslog facility constant.
+ *
+ * Requires:
+ *
+ *     'str' is not NULL
+ *     'facilityp' is not NULL
+ *
+ * Returns:
+ *     ISC_R_SUCCESS
+ *     ISC_R_NOTFOUND
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SYSLOG_H */
diff --git a/lib/isc/win32/include/isc/thread.h b/lib/isc/win32/include/isc/thread.h
new file mode 100644 (file)
index 0000000..78e663f
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: thread.h,v 1.22 2007/06/19 23:47:20 tbox Exp $ */
+
+#ifndef ISC_THREAD_H
+#define ISC_THREAD_H 1
+
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+/*
+ * Inlines to help with wait retrun checking
+ */
+
+/* check handle for NULL and INVALID_HANDLE */
+inline BOOL IsValidHandle( HANDLE hHandle) {
+    return ((hHandle != NULL) && (hHandle != INVALID_HANDLE_VALUE));
+}
+
+/* validate wait return codes... */
+inline BOOL WaitSucceeded( DWORD dwWaitResult, DWORD dwHandleCount) {
+    return ((dwWaitResult >= WAIT_OBJECT_0) &&
+            (dwWaitResult < WAIT_OBJECT_0 + dwHandleCount));
+}
+
+inline BOOL WaitAbandoned( DWORD dwWaitResult, DWORD dwHandleCount) {
+    return ((dwWaitResult >= WAIT_ABANDONED_0) &&
+            (dwWaitResult < WAIT_ABANDONED_0 + dwHandleCount));
+}
+
+inline BOOL WaitTimeout( DWORD dwWaitResult) {
+    return (dwWaitResult == WAIT_TIMEOUT);
+}
+    
+inline BOOL WaitFailed( DWORD dwWaitResult) {
+    return (dwWaitResult == WAIT_FAILED);
+}
+
+/* compute object indices for waits... */
+inline DWORD WaitSucceededIndex( DWORD dwWaitResult) {
+    return (dwWaitResult - WAIT_OBJECT_0);
+}
+
+inline DWORD WaitAbandonedIndex( DWORD dwWaitResult) {
+    return (dwWaitResult - WAIT_ABANDONED_0);
+}
+
+
+
+typedef HANDLE isc_thread_t;
+typedef unsigned int isc_threadresult_t;
+typedef void * isc_threadarg_t;
+typedef isc_threadresult_t (WINAPI *isc_threadfunc_t)(isc_threadarg_t);
+typedef DWORD isc_thread_key_t;
+
+#define isc_thread_self (unsigned long)GetCurrentThreadId
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *);
+
+isc_result_t
+isc_thread_join(isc_thread_t, isc_threadresult_t *);
+
+void
+isc_thread_setconcurrency(unsigned int level);
+
+int
+isc_thread_key_create(isc_thread_key_t *key, void (*func)(void *));
+
+int
+isc_thread_key_delete(isc_thread_key_t key);
+
+void *
+isc_thread_key_getspecific(isc_thread_key);
+
+int
+isc_thread_key_setspecific(isc_thread_key_t key, void *value);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_THREAD_H */
diff --git a/lib/isc/win32/include/isc/time.h b/lib/isc/win32/include/isc/time.h
new file mode 100644 (file)
index 0000000..ce3c4c6
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2004, 2006-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: time.h,v 1.33.56.2 2009/01/05 23:47:23 tbox Exp $ */
+
+#ifndef ISC_TIME_H
+#define ISC_TIME_H 1
+
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/***
+ *** Intervals
+ ***/
+
+/*
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+struct isc_interval {
+       isc_int64_t interval;
+};
+
+LIBISC_EXTERNAL_DATA extern isc_interval_t *isc_interval_zero;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_interval_set(isc_interval_t *i,
+                unsigned int seconds, unsigned int nanoseconds);
+/*
+ * Set 'i' to a value representing an interval of 'seconds' seconds and
+ * 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and
+ * isc_time_subtract().
+ *
+ * Requires:
+ *
+ *     't' is a valid pointer.
+ *     nanoseconds < 1000000000.
+ */
+
+isc_boolean_t
+isc_interval_iszero(const isc_interval_t *i);
+/*
+ * Returns ISC_TRUE iff. 'i' is the zero interval.
+ *
+ * Requires:
+ *
+ *     'i' is a valid pointer.
+ */
+
+/***
+ *** Absolute Times
+ ***/
+
+/*
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+
+struct isc_time {
+       FILETIME absolute;
+};
+
+LIBISC_EXTERNAL_DATA extern isc_time_t *isc_time_epoch;
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds);
+/*%<
+ * Set 't' to a value which represents the given number of seconds and
+ * nanoseconds since 00:00:00 January 1, 1970, UTC.
+ *
+ * Requires:
+ *\li   't' is a valid pointer.
+ *\li   nanoseconds < 1000000000.
+ */
+
+void
+isc_time_settoepoch(isc_time_t *t);
+/*
+ * Set 't' to the time of the epoch.
+ *
+ * Notes:
+ *     The date of the epoch is platform-dependent.
+ *
+ * Requires:
+ *
+ *     't' is a valid pointer.
+ */
+
+isc_boolean_t
+isc_time_isepoch(const isc_time_t *t);
+/*
+ * Returns ISC_TRUE iff. 't' is the epoch ("time zero").
+ *
+ * Requires:
+ *
+ *     't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_now(isc_time_t *t);
+/*
+ * Set 't' to the current absolute time.
+ *
+ * Requires:
+ *
+ *     't' is a valid pointer.
+ *
+ * Returns:
+ *
+ *     Success
+ *     Unexpected error
+ *             Getting the time from the system failed.
+ *     Out of range
+ *             The time from the system is too large to be represented
+ *             in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i);
+/*
+ * Set *t to the current absolute time + i.
+ *
+ * Note:
+ *     This call is equivalent to:
+ *
+ *             isc_time_now(t);
+ *             isc_time_add(t, i, t);
+ *
+ * Requires:
+ *
+ *     't' and 'i' are valid pointers.
+ *
+ * Returns:
+ *
+ *     Success
+ *     Unexpected error
+ *             Getting the time from the system failed.
+ *     Out of range
+ *             The interval added to the time from the system is too large to
+ *             be represented in the current definition of isc_time_t.
+ */
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2);
+/*
+ * Compare the times referenced by 't1' and 't2'
+ *
+ * Requires:
+ *
+ *     't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *
+ *     -1              t1 < t2         (comparing times, not pointers)
+ *     0               t1 = t2
+ *     1               t1 > t2
+ */
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result);
+/*
+ * Add 'i' to 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ *     't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ *     Success
+ *     Out of range
+ *             The interval added to the time is too large to
+ *             be represented in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+                 isc_time_t *result);
+/*
+ * Subtract 'i' from 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ *     't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ *     Success
+ *     Out of range
+ *             The interval is larger than the time since the epoch.
+ */
+
+isc_uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2);
+/*
+ * Find the difference in milliseconds between time t1 and time t2.
+ * t2 is the subtrahend of t1; ie, difference = t1 - t2.
+ *
+ * Requires:
+ *
+ *     't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *     The difference of t1 - t2, or 0 if t1 <= t2.
+ */
+
+isc_uint32_t
+isc_time_nanoseconds(const isc_time_t *t);
+/*
+ * Return the number of nanoseconds stored in a time structure.
+ *
+ * Notes:
+ *     This is the number of nanoseconds in excess of the number
+ *     of seconds since the epoch; it will always be less than one
+ *     full second.
+ *
+ * Requires:
+ *     't' is a valid pointer.
+ *
+ * Ensures:
+ *     The returned value is less than 1*10^9.
+ */
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "30-Aug-2000 04:06:47.997" and the local time zone.
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ *  Requires:
+ *      'len' > 0
+ *      'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ *  Requires:
+ *      'len' > 0
+ *      'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ssZ"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ *  Requires:
+ *\li      'len' > 0
+ *\li      'buf' points to an array of at least len chars
+ *
+ */
+
+isc_uint32_t
+isc_time_seconds(const isc_time_t *t);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TIME_H */
index 63794565b9e0e5896bd5cad576cf5a61a8480793..d86820532c35f588aa1b15fd7d09d53a1db05c68 100644 (file)
@@ -1,21 +1,21 @@
 /*
- * Copyright (C) 2002 Internet Software Consortium.
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: win32os.h,v 1.2 2002/08/03 01:36:24 mayer Exp $ */
+/* $Id: win32os.h,v 1.5 2007/06/19 23:47:20 tbox Exp $ */
 
 #ifndef ISC_WIN32OS_H
 #define ISC_WIN32OS_H 1
index d7225cb7b4fd4e67b751c2a9a1dfa57bd3c35d6c..a69b70269492366e858d7b3ca8db3a7aa390daba 100644 (file)
 
 /* $Id: interfaceiter.c,v 1.13.110.2 2009/01/18 23:47:41 tbox Exp $ */
 
+/*
+ * Note that this code will need to be revisited to support IPv6 Interfaces.
+ * For now we just iterate through IPv4 interfaces.
+ */
+
 #include <config.h>
 #include <winsock2.h>
 #include <ws2tcpip.h>
@@ -91,9 +96,7 @@ get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
                memcpy(&dst->type.in6,
                       &((struct sockaddr_in6 *) src)->sin6_addr,
                       sizeof(struct in6_addr));
-#ifdef ISC_PLATFORM_HAVESCOPEID
                dst->zone = ((struct sockaddr_in6 *) src)->sin6_scope_id;
-#endif
                break;
        default:
                INSIST(0);
@@ -101,26 +104,6 @@ get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
        }
 }
 
-/*
- * The WSAIoctl code is not fetching the broadcast address for each interface address
- * so we need to reconstruct it from the address and its network mask
- */
-static void
-get_broadcastaddr(isc_netaddr_t *bcastaddr, isc_netaddr_t *addr, isc_netaddr_t *netmask) {
-
-       unsigned char *p, *a, *n;
-       int i;
-
-       p = (unsigned char *) &bcastaddr->type.in;
-       a = (unsigned char *) &addr->type.in;
-       n = (unsigned char *) &netmask->type.in;
-
-       for (i=0; i < 4; i++) {
-               p[i] = (unsigned char) (a[i] | ~n[i]);
-       }
-
-}
-
 isc_result_t
 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        char strbuf[ISC_STRERRORSIZE];
@@ -129,6 +112,7 @@ isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        int error;
        unsigned long bytesReturned = 0;
 
+       REQUIRE(mctx != NULL);
        REQUIRE(iterp != NULL);
        REQUIRE(*iterp == NULL);
 
@@ -347,14 +331,6 @@ internal_current(isc_interfaceiter_t *iter) {
        if ((flags & IFF_UP) != 0)
                iter->current.flags |= INTERFACE_F_UP;
 
-       if ((flags & IFF_BROADCAST) != 0) {
-               iter->current.flags |= INTERFACE_F_BROADCAST;
-       }
-
-       if ((flags & IFF_MULTICAST) != 0) {
-               iter->current.flags |= INTERFACE_F_MULTICAST;
-       }
-
        if ((flags & IFF_POINTTOPOINT) != 0) {
                iter->current.flags |= INTERFACE_F_POINTTOPOINT;
                sprintf(iter->current.name, "PPP Interface %d", iter->numIF);
@@ -376,26 +352,16 @@ internal_current(isc_interfaceiter_t *iter) {
                (struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
        }
 
+       if (ifNamed == FALSE)
+               sprintf(iter->current.name,
+                       "TCP/IP Interface %d", iter->numIF);
+
        /*
         * Get the network mask.
         */
        get_addr(AF_INET, &iter->current.netmask,
                 (struct sockaddr *)&(iter->IFData.iiNetmask));
 
-       /*
-        * If the interface is broadcast, get the broadcast address.
-        */
-       if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
-               get_addr(AF_INET, &iter->current.broadcast, 
-               (struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
-               get_broadcastaddr(&iter->current.broadcast, &iter->current.address,
-                                  &iter->current.netmask);
-       }
-
-       if (ifNamed == FALSE)
-               sprintf(iter->current.name,
-                       "TCP/IP Interface %d", iter->numIF);
-
        return (ISC_R_SUCCESS);
 }
 
@@ -418,7 +384,7 @@ internal_current6(isc_interfaceiter_t *iter) {
         * Get interface flags.
         */
 
-       iter->current.flags = INTERFACE_F_UP | INTERFACE_F_MULTICAST;
+       iter->current.flags = INTERFACE_F_UP;
 
        if (ifNamed == FALSE)
                sprintf(iter->current.name,
diff --git a/lib/isc/win32/ipv6.c b/lib/isc/win32/ipv6.c
new file mode 100644 (file)
index 0000000..511ae21
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ipv6.c,v 1.8 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <isc/net.h>
+#include <isc/platform.h>
+
+LIBISC_EXTERNAL_DATA const struct in6_addr isc_in6addr_any =
+       IN6ADDR_ANY_INIT;
+
+LIBISC_EXTERNAL_DATA const struct in6_addr isc_in6addr_loopback =
+       IN6ADDR_LOOPBACK_INIT;
diff --git a/lib/isc/win32/keyboard.c b/lib/isc/win32/keyboard.c
new file mode 100644 (file)
index 0000000..d569e7c
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: keyboard.c,v 1.7 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#include <windows.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <io.h>
+
+#include <isc/keyboard.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_keyboard_open(isc_keyboard_t *keyboard) {
+       int fd;
+
+       REQUIRE(keyboard != NULL);
+
+       fd = _fileno(stdin);
+       if (fd < 0)
+               return (ISC_R_IOERROR);
+
+       keyboard->fd = fd;
+
+       keyboard->result = ISC_R_SUCCESS;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleeptime) {
+       REQUIRE(keyboard != NULL);
+
+       if (sleeptime > 0 && keyboard->result != ISC_R_CANCELED)
+               (void)Sleep(sleeptime*1000);
+
+       keyboard->fd = -1;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp) {
+       ssize_t cc;
+       unsigned char c;
+
+       REQUIRE(keyboard != NULL);
+       REQUIRE(cp != NULL);
+
+       cc = read(keyboard->fd, &c, 1);
+       if (cc < 0) {
+               keyboard->result = ISC_R_IOERROR;
+               return (keyboard->result);
+       }
+
+       *cp = c;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_boolean_t
+isc_keyboard_canceled(isc_keyboard_t *keyboard) {
+       return (ISC_TF(keyboard->result == ISC_R_CANCELED));
+}
+
diff --git a/lib/isc/win32/libisc.def b/lib/isc/win32/libisc.def
new file mode 100644 (file)
index 0000000..19a2fef
--- /dev/null
@@ -0,0 +1,551 @@
+LIBRARY libisc
+
+; Exported Functions
+EXPORTS
+
+NTReportError
+closelog
+isc__buffer_activeregion
+isc__buffer_add
+isc__buffer_availableregion
+isc__buffer_back
+isc__buffer_clear
+isc__buffer_consumedregion
+isc__buffer_first
+isc__buffer_forward
+isc__buffer_init
+isc__buffer_invalidate
+isc__buffer_putmem
+isc__buffer_putstr
+isc__buffer_putuint16
+isc__buffer_putuint32
+isc__buffer_putuint48
+isc__buffer_putuint8
+isc__buffer_region
+isc__buffer_remainingregion
+isc__buffer_setactive
+isc__buffer_subtract
+isc__buffer_usedregion
+isc__mem_allocate
+isc__mem_free
+isc__mem_get
+isc__mem_put
+isc__mem_putanddetach
+isc__mem_reallocate
+isc__mem_strdup
+isc__mempool_get
+isc__mempool_put
+isc__socketmgr_setreserved
+isc__strerror
+isc_app_block
+isc_app_finish
+isc_app_onrun
+isc_app_reload
+isc_app_run
+isc_app_shutdown
+isc_app_start
+isc_app_unblock
+isc_assertion_setcallback
+isc_assertion_typetotext
+isc_base32_decoderegion
+isc_base32_decodestring
+isc_base32_tobuffer
+isc_base32_totext
+isc_base32hex_decoderegion
+isc_base32hex_decodestring
+isc_base32hex_tobuffer
+isc_base32hex_totext
+isc_base64_decodestring
+isc_base64_tobuffer
+isc_base64_totext
+isc_bitstring_copy
+isc_bitstring_init
+isc_bitstring_invalidate
+isc_buffer_allocate
+isc_buffer_compact
+isc_buffer_copyregion
+isc_buffer_free
+isc_buffer_getuint16
+isc_buffer_getuint32
+isc_buffer_getuint8
+isc_buffer_reinit
+isc_bufferlist_availablecount
+isc_bufferlist_usedcount
+isc_commandline_parse
+isc_condition_broadcast
+isc_condition_destroy
+isc_condition_init
+isc_condition_signal
+isc_condition_wait
+isc_condition_waituntil
+isc_dir_chdir
+isc_dir_chroot
+isc_dir_close
+isc_dir_init
+isc_dir_open
+isc_dir_read
+isc_dir_reset
+isc_entropy_addcallbacksample
+isc_entropy_addsample
+isc_entropy_attach
+isc_entropy_create
+isc_entropy_createcallbacksource
+isc_entropy_createfilesource
+isc_entropy_createsamplesource
+isc_entropy_destroysource
+isc_entropy_detach
+isc_entropy_getdata
+isc_entropy_putdata
+isc_entropy_stats
+isc_entropy_status
+isc_entropy_stopcallbacksources
+isc_entropy_usebestsource
+isc_error_fatal
+isc_error_runtimecheck
+isc_error_setfatal
+isc_error_setunexpected
+isc_error_unexpected
+isc_event_allocate
+isc_event_free
+isc_file_absolutepath
+isc_file_basename
+isc_file_exists
+isc_file_getmodtime
+isc_file_isabsolute
+isc_file_ischdiridempotent
+isc_file_iscurrentdir
+isc_file_mktemplate
+isc_file_openunique
+isc_file_progname
+isc_file_remove
+isc_file_rename
+isc_file_renameunique
+isc_file_safemovefile
+isc_file_settime
+isc_file_template
+isc_file_truncate
+isc_fsaccess_add
+isc_fsaccess_changeowner
+isc_fsaccess_remove
+isc_fsaccess_set
+isc_hash_calc
+isc_hash_create
+isc_hash_ctxattach
+isc_hash_ctxcalc
+isc_hash_ctxcreate
+isc_hash_ctxdetach
+isc_hash_ctxinit
+isc_hash_destroy
+isc_hash_init
+isc_heap_create
+isc_heap_decreased
+isc_heap_delete
+isc_heap_destroy
+isc_heap_element
+isc_heap_increased
+isc_heap_insert
+isc_hex_decodestring
+isc_hex_tobuffer
+isc_hex_totext
+isc_hmacmd5_init
+isc_hmacmd5_invalidate
+isc_hmacmd5_sign
+isc_hmacmd5_update
+isc_hmacmd5_verify
+isc_hmacmd5_verify2
+isc_hmacsha1_init
+isc_hmacsha1_invalidate
+isc_hmacsha1_sign
+isc_hmacsha1_update
+isc_hmacsha1_verify
+isc_hmacsha224_init
+isc_hmacsha224_invalidate
+isc_hmacsha224_sign
+isc_hmacsha224_update
+isc_hmacsha224_verify
+isc_hmacsha256_init
+isc_hmacsha256_invalidate
+isc_hmacsha256_sign
+isc_hmacsha256_update
+isc_hmacsha256_verify
+isc_hmacsha384_init
+isc_hmacsha384_invalidate
+isc_hmacsha384_sign
+isc_hmacsha384_update
+isc_hmacsha384_verify
+isc_hmacsha512_init
+isc_hmacsha512_invalidate
+isc_hmacsha512_sign
+isc_hmacsha512_update
+isc_hmacsha512_verify
+isc_httpdmgr_addurl
+isc_httpdmgr_create
+isc_httpdmgr_shutdown
+isc_interfaceiter_create
+isc_interfaceiter_current
+isc_interfaceiter_destroy
+isc_interfaceiter_first
+isc_interfaceiter_next
+isc_interval_iszero
+isc_interval_set
+isc_iterated_hash
+isc_keyboard_canceled
+isc_keyboard_close
+isc_keyboard_getchar
+isc_keyboard_open
+isc_lex_close
+isc_lex_create
+isc_lex_destroy
+isc_lex_getcomments
+isc_lex_getlasttokentext
+isc_lex_getmastertoken
+isc_lex_getoctaltoken
+isc_lex_getsourceline
+isc_lex_getsourcename
+isc_lex_getspecials
+isc_lex_gettoken
+isc_lex_isfile
+isc_lex_openbuffer
+isc_lex_openfile
+isc_lex_openstream
+isc_lex_setcomments
+isc_lex_setspecials
+isc_lex_ungettoken
+isc_lfsr_generate
+isc_lfsr_generate32
+isc_lfsr_init
+isc_lfsr_skip
+isc_lib_initmsgcat
+isc_log_categorybyname
+isc_log_closefilelogs
+isc_log_create
+isc_log_createchannel
+isc_log_destroy
+isc_log_getdebuglevel
+isc_log_getduplicateinterval
+isc_log_gettag
+isc_log_ivwrite
+isc_log_ivwrite1
+isc_log_iwrite
+isc_log_iwrite1
+isc_log_modulebyname
+isc_log_opensyslog
+isc_log_registercategories
+isc_log_registermodules
+isc_log_setcontext
+isc_log_setdebuglevel
+isc_log_setduplicateinterval
+isc_log_settag
+isc_log_usechannel
+isc_log_vwrite
+isc_log_vwrite1
+isc_log_wouldlog
+isc_log_write
+isc_log_write1
+isc_logconfig_create
+isc_logconfig_destroy
+isc_logconfig_get
+isc_logconfig_use
+isc_md5_final
+isc_md5_init
+isc_md5_invalidate
+isc_md5_update
+isc_mem_attach
+isc_mem_checkdestroyed
+isc_mem_create
+isc_mem_create2
+isc_mem_createx
+isc_mem_createx2
+isc_mem_destroy
+isc_mem_detach
+isc_mem_getname
+isc_mem_getquota
+isc_mem_gettag
+isc_mem_inuse
+isc_mem_ondestroy
+isc_mem_references
+isc_mem_setdestroycheck
+isc_mem_setname
+isc_mem_setquota
+isc_mem_setwater
+isc_mem_stats
+isc_mem_waterack
+isc_mempool_associatelock
+isc_mempool_create
+isc_mempool_destroy
+isc_mempool_getallocated
+isc_mempool_getfillcount
+isc_mempool_getfreecount
+isc_mempool_getfreemax
+isc_mempool_getmaxalloc
+isc_mempool_setfillcount
+isc_mempool_setfreemax
+isc_mempool_setmaxalloc
+isc_mempool_setname
+isc_msgcat_close
+isc_msgcat_get
+isc_msgcat_open
+isc_mutexblock_destroy
+isc_mutexblock_init
+isc_net_aton
+isc_net_disableipv4
+isc_net_disableipv6
+isc_net_getudpportrange
+isc_net_ntop
+isc_net_probe_ipv6only
+isc_net_probe_ipv6pktinfo
+isc_net_probeipv4
+isc_net_probeipv6
+isc_net_probeunix
+isc_net_pton
+isc_netaddr_any
+isc_netaddr_any6
+isc_netaddr_eqprefix
+isc_netaddr_equal
+isc_netaddr_format
+isc_netaddr_fromin
+isc_netaddr_fromin6
+isc_netaddr_frompath
+isc_netaddr_fromsockaddr
+isc_netaddr_fromv4mapped
+isc_netaddr_ismulticast
+isc_netaddr_masktoprefixlen
+isc_netaddr_prefixok
+isc_netaddr_setzone
+isc_netaddr_totext
+isc_netscope_pton
+isc_ntpaths_get
+isc_ntpaths_init
+isc_once_do
+isc_ondestroy_init
+isc_ondestroy_notify
+isc_ondestroy_register
+isc_os_ncpus
+isc_parse_uint16
+isc_parse_uint32
+isc_parse_uint8
+isc_portset_add
+isc_portset_addrange
+isc_portset_create
+isc_portset_destroy
+isc_portset_isset
+isc_portset_nports
+isc_portset_remove
+isc_portset_removerange
+isc_quota_attach
+isc_quota_destroy
+isc_quota_detach
+isc_quota_init
+isc_quota_max
+isc_quota_release
+isc_quota_reserve
+isc_quota_soft
+isc_radix_create
+isc_radix_destroy
+isc_radix_insert
+isc_radix_process
+isc_radix_remove
+isc_radix_search
+isc_random_get
+isc_random_jitter
+isc_random_seed
+isc_ratelimiter_attach
+isc_ratelimiter_create
+isc_ratelimiter_detach
+isc_ratelimiter_enqueue
+isc_ratelimiter_setinterval
+isc_ratelimiter_setpertic
+isc_ratelimiter_shutdown
+isc_refcount_init
+isc_region_compare
+isc_resource_getcurlimit
+isc_resource_getlimit
+isc_resource_setlimit
+isc_result_register
+isc_result_totext
+isc_rwlock_destroy
+isc_rwlock_downgrade
+isc_rwlock_init
+isc_rwlock_lock
+isc_rwlock_trylock
+isc_rwlock_tryupgrade
+isc_rwlock_unlock
+isc_serial_eq
+isc_serial_ge
+isc_serial_gt
+isc_serial_le
+isc_serial_lt
+isc_serial_ne
+isc_sha1_final
+isc_sha1_init
+isc_sha1_invalidate
+isc_sha1_update
+isc_sha224_final
+isc_sha224_init
+isc_sha224_update
+isc_sha256_final
+isc_sha256_init
+isc_sha256_update
+isc_sha384_final
+isc_sha384_init
+isc_sha384_update
+isc_sha512_final
+isc_sha512_init
+isc_sha512_update
+isc_sockaddr_any
+isc_sockaddr_any6
+isc_sockaddr_anyofpf
+isc_sockaddr_compare
+isc_sockaddr_eqaddr
+isc_sockaddr_eqaddrprefix
+isc_sockaddr_equal
+isc_sockaddr_format
+isc_sockaddr_fromin
+isc_sockaddr_fromin6
+isc_sockaddr_fromnetaddr
+isc_sockaddr_frompath
+isc_sockaddr_getport
+isc_sockaddr_hash
+isc_sockaddr_isexperimental
+isc_sockaddr_ismulticast
+isc_sockaddr_pf
+isc_sockaddr_setport
+isc_sockaddr_totext
+isc_sockaddr_v6fromin
+isc_socket_accept
+isc_socket_attach
+isc_socket_bind
+isc_socket_cancel
+isc_socket_cleanunix
+isc_socket_close
+isc_socket_connect
+isc_socket_create
+isc_socket_detach
+isc_socket_filter
+isc_socket_getname
+isc_socket_getpeername
+isc_socket_getsockname
+isc_socket_gettag
+isc_socket_gettype
+isc_socket_ipv6only
+isc_socket_isbound
+isc_socket_listen
+isc_socket_open
+isc_socket_permunix
+isc_socket_recv
+isc_socket_recv2
+isc_socket_recvv
+isc_socket_send
+isc_socket_sendto
+isc_socket_sendto2
+isc_socket_sendtov
+isc_socket_sendv
+isc_socket_setname
+isc_socketmgr_create
+isc_socketmgr_create2
+isc_socketmgr_destroy
+isc_socketmgr_getmaxsockets
+isc_socketmgr_setstats
+isc_stats_create
+isc_stats_attach
+isc_stats_detach
+isc_stats_ncounters
+isc_stats_increment
+isc_stats_decrement
+isc_stats_dump
+isc_stdio_close
+isc_stdio_flush
+isc_stdio_open
+isc_stdio_read
+isc_stdio_seek
+isc_stdio_sync
+isc_stdio_write
+isc_stdtime_get
+isc_string_append
+isc_string_append_truncate
+isc_string_copy
+isc_string_copy_truncate
+isc_string_printf
+isc_string_printf_truncate
+isc_string_regiondup
+isc_string_separate
+isc_string_strlcat
+isc_string_strlcpy
+isc_string_touint64
+isc_symtab_create
+isc_symtab_define
+isc_symtab_destroy
+isc_symtab_lookup
+isc_symtab_undefine
+isc_syslog_facilityfromstring
+isc_task_attach
+isc_task_beginexclusive
+isc_task_create
+isc_task_destroy
+isc_task_detach
+isc_task_endexclusive
+isc_task_getcurrenttime
+isc_task_getname
+isc_task_gettag
+isc_task_onshutdown
+isc_task_purge
+isc_task_purgeevent
+isc_task_purgerange
+isc_task_send
+isc_task_sendanddetach
+isc_task_setname
+isc_task_shutdown
+isc_task_unsend
+isc_task_unsendrange
+isc_taskmgr_create
+isc_taskmgr_destroy
+isc_taskpool_create
+isc_taskpool_destroy
+isc_taskpool_gettask
+isc_thread_create
+isc_thread_join
+isc_thread_key_create
+isc_thread_key_delete
+isc_thread_key_getspecific
+isc_thread_key_setspecific
+isc_thread_setconcurrency
+isc_time_add
+isc_time_compare
+isc_time_isepoch
+isc_time_microdiff
+isc_time_nanoseconds
+isc_time_now
+isc_time_nowplusinterval
+isc_time_seconds
+isc_time_set
+isc_time_settoepoch
+isc_time_subtract
+isc_timer_attach
+isc_timer_create
+isc_timer_detach
+isc_timer_reset
+isc_timer_touch
+isc_timermgr_create
+isc_timermgr_destroy
+isc_timermgr_poke
+isc_win32os_majorversion
+isc_win32os_minorversion
+isc_win32os_servicepackmajor
+isc_win32os_servicepackminor
+isc_win32os_versioncheck
+openlog
+syslog
+
+; Exported Data
+
+EXPORTS
+
+isc_assertion_failed           DATA
+isc_commandline_argument       DATA
+isc_commandline_errprint       DATA
+isc_commandline_index          DATA
+isc_commandline_option         DATA
+isc_commandline_progname       DATA
+isc_commandline_reset          DATA
+isc_mem_debugging              DATA
+                       
diff --git a/lib/isc/win32/libisc.dsp b/lib/isc/win32/libisc.dsp
new file mode 100644 (file)
index 0000000..c0ffb71
--- /dev/null
@@ -0,0 +1,784 @@
+# Microsoft Developer Studio Project File - Name="libisc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libisc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "libisc.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "libisc.mak" CFG="libisc - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "libisc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libisc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "../../../" /I "include" /I "../include" /I "../noatomic/include" /I "win32" /I "../../isccfg/include" /D "WIN32" /D "NDEBUG" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 user32.lib advapi32.lib ws2_32.lib /nologo /dll /machine:I386 /out:"../../../Build/Release/libisc.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../../../" /I "include" /I "../include" /I "../noatomic/include" /I "win32" /I "../../isccfg/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /FR /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 user32.lib advapi32.lib ws2_32.lib /nologo /dll /map /debug /machine:I386 /out:"../../../Build/Debug/libisc.dll" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "libisc - Win32 Release"
+# Name "libisc - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\app.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\condition.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\DLLMain.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\entropy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\errno2result.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\file.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fsaccess.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\interfaceiter.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ipv6.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\iterated_hash.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\keyboard.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\net.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ntpaths.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\once.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\socket.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\strerror.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdio.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdtime.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\syslog.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\thread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\time.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\version.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\include\isc\app.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\assertions.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\base32.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\base64.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\bind_registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\bindevt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\bitstring.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\boolean.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\buffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\bufferlist.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\commandline.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\condition.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\config.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\dir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\entropy.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\errno2result.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\error.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\event.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\eventclass.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\file.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\formatcheck.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\fsaccess.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\hash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\heap.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\hex.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\hmacmd5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\hmacsha.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\httpd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\int.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\interfaceiter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\ipv6.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\iterated_hash.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\keyboard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\lang.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\lex.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\lfsr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\lib.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\list.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\log.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\magic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\mem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\msgcat.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\msioctl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\mutex.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\mutexblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\net.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\netaddr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\netscope.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\netdb.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\ntpaths.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\offset.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\once.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\ondestroy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\parseint.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\portset.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\os.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\platform.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\print.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\quota.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\radix.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\random.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\ratelimiter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\refcount.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\region.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\result.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\resultclass.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\rwlock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\serial.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\sha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\sha2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\sockaddr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\socket.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\stats.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\stdio.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\strerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\stdtime.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\string.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\symtab.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\syslog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\syslog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\task.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\taskpool.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\time.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\timer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\isc\win32os.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\types.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\unistd.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\isc\util.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\versions.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Group "Main Isc Lib"
+
+# PROP Default_Filter "c"
+# Begin Source File
+
+SOURCE=..\assertions.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\base32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\base64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\bitstring.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\buffer.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\bufferlist.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\commandline.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\error.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\event.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\hash.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\heap.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\hex.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\hmacmd5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\hmacsha.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\httpd.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\inet_aton.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\inet_ntop.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\inet_pton.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lex.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lfsr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\log.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mem.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\nls\msgcat.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\mutexblock.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\netaddr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\netscope.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ondestroy.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\parseint.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\portset.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\quota.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\radix.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\random.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ratelimiter.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\refcount.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\region.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\result.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\rwlock.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\serial.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\sha1.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\sha2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\sockaddr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\stats.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\string.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\symtab.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\task.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\taskpool.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\timer.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\win32os.c
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\noatomic\include\atomic.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libisc.def
+# End Source File
+# End Target
+# End Project
diff --git a/lib/isc/win32/libisc.dsw b/lib/isc/win32/libisc.dsw
new file mode 100644 (file)
index 0000000..c66c56e
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "libisc"=".\libisc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lib/isc/win32/libisc.mak b/lib/isc/win32/libisc.mak
new file mode 100644 (file)
index 0000000..47d7b97
--- /dev/null
@@ -0,0 +1,2006 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on libisc.dsp
+!IF "$(CFG)" == ""
+CFG=libisc - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to libisc - Win32 Debug.
+!ENDIF 
+
+!IF "$(CFG)" != "libisc - Win32 Release" && "$(CFG)" != "libisc - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "libisc.mak" CFG="libisc - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "libisc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libisc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+!ERROR An invalid configuration is specified.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+_VC_MANIFEST_INC=0
+_VC_MANIFEST_BASENAME=__VC80
+!ELSE
+_VC_MANIFEST_INC=1
+_VC_MANIFEST_BASENAME=__VC80.Debug
+!ENDIF
+
+####################################################
+# Specifying name of temporary resource file used only in incremental builds:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res
+!else
+_VC_MANIFEST_AUTO_RES=
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1
+
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_DLL - command to embed manifest in DLL:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;2
+
+!endif
+####################################################
+# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \
+    $(_VC_MANIFEST_BASENAME).auto.rc \
+    $(_VC_MANIFEST_BASENAME).auto.manifest
+
+!else
+
+_VC_MANIFEST_CLEAN=
+
+!endif
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "..\..\..\Build\Release\libisc.dll"
+
+
+CLEAN :
+       -@erase "$(INTDIR)\app.obj"
+       -@erase "$(INTDIR)\assertions.obj"
+       -@erase "$(INTDIR)\base32.obj"
+       -@erase "$(INTDIR)\base64.obj"
+       -@erase "$(INTDIR)\bitstring.obj"
+       -@erase "$(INTDIR)\buffer.obj"
+       -@erase "$(INTDIR)\bufferlist.obj"
+       -@erase "$(INTDIR)\commandline.obj"
+       -@erase "$(INTDIR)\condition.obj"
+       -@erase "$(INTDIR)\dir.obj"
+       -@erase "$(INTDIR)\DLLMain.obj"
+       -@erase "$(INTDIR)\entropy.obj"
+       -@erase "$(INTDIR)\errno2result.obj"
+       -@erase "$(INTDIR)\error.obj"
+       -@erase "$(INTDIR)\event.obj"
+       -@erase "$(INTDIR)\file.obj"
+       -@erase "$(INTDIR)\fsaccess.obj"
+       -@erase "$(INTDIR)\hash.obj"
+       -@erase "$(INTDIR)\heap.obj"
+       -@erase "$(INTDIR)\hex.obj"
+       -@erase "$(INTDIR)\hmacmd5.obj"
+       -@erase "$(INTDIR)\hmacsha.obj"
+       -@erase "$(INTDIR)\httpd.obj"
+       -@erase "$(INTDIR)\inet_aton.obj"
+       -@erase "$(INTDIR)\inet_ntop.obj"
+       -@erase "$(INTDIR)\inet_pton.obj"
+       -@erase "$(INTDIR)\interfaceiter.obj"
+       -@erase "$(INTDIR)\ipv6.obj"
+       -@erase "$(INTDIR)\iterated_hash.obj"
+       -@erase "$(INTDIR)\keyboard.obj"
+       -@erase "$(INTDIR)\lex.obj"
+       -@erase "$(INTDIR)\lfsr.obj"
+       -@erase "$(INTDIR)\lib.obj"
+       -@erase "$(INTDIR)\log.obj"
+       -@erase "$(INTDIR)\md5.obj"
+       -@erase "$(INTDIR)\mem.obj"
+       -@erase "$(INTDIR)\msgcat.obj"
+       -@erase "$(INTDIR)\mutexblock.obj"
+       -@erase "$(INTDIR)\net.obj"
+       -@erase "$(INTDIR)\netaddr.obj"
+       -@erase "$(INTDIR)\netscope.obj"
+       -@erase "$(INTDIR)\ntpaths.obj"
+       -@erase "$(INTDIR)\once.obj"
+       -@erase "$(INTDIR)\ondestroy.obj"
+       -@erase "$(INTDIR)\os.obj"
+       -@erase "$(INTDIR)\parseint.obj"
+       -@erase "$(INTDIR)\portset.obj"
+       -@erase "$(INTDIR)\quota.obj"
+       -@erase "$(INTDIR)\radix.obj"
+       -@erase "$(INTDIR)\random.obj"
+       -@erase "$(INTDIR)\ratelimiter.obj"
+       -@erase "$(INTDIR)\refcount.obj"
+       -@erase "$(INTDIR)\region.obj"
+       -@erase "$(INTDIR)\resource.obj"
+       -@erase "$(INTDIR)\result.obj"
+       -@erase "$(INTDIR)\rwlock.obj"
+       -@erase "$(INTDIR)\serial.obj"
+       -@erase "$(INTDIR)\sha1.obj"
+       -@erase "$(INTDIR)\sha2.obj"
+       -@erase "$(INTDIR)\sockaddr.obj"
+       -@erase "$(INTDIR)\socket.obj"
+       -@erase "$(INTDIR)\stats.obj"
+       -@erase "$(INTDIR)\stdio.obj"
+       -@erase "$(INTDIR)\stdtime.obj"
+       -@erase "$(INTDIR)\strerror.obj"
+       -@erase "$(INTDIR)\string.obj"
+       -@erase "$(INTDIR)\symtab.obj"
+       -@erase "$(INTDIR)\syslog.obj"
+       -@erase "$(INTDIR)\task.obj"
+       -@erase "$(INTDIR)\taskpool.obj"
+       -@erase "$(INTDIR)\thread.obj"
+       -@erase "$(INTDIR)\time.obj"
+       -@erase "$(INTDIR)\timer.obj"
+       -@erase "$(INTDIR)\vc60.idb"
+       -@erase "$(INTDIR)\version.obj"
+       -@erase "$(INTDIR)\win32os.obj"
+       -@erase "$(OUTDIR)\libisc.exp"
+       -@erase "$(OUTDIR)\libisc.lib"
+       -@erase "..\..\..\Build\Release\libisc.dll"
+       -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "./" /I "../../../" /I "include" /I "../include" /I "../../../lib/isc/noatomic/include" /I "win32" /I "../../isccfg/include" /D "WIN32" /D "NDEBUG" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /Fp"$(INTDIR)\libisc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisc.bsc" 
+BSC32_SBRS= \
+       
+LINK32=link.exe
+LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\libisc.pdb" /machine:I386 /def:".\libisc.def" /out:"../../../Build/Release/libisc.dll" /implib:"$(OUTDIR)\libisc.lib" 
+DEF_FILE= \
+       ".\libisc.def"
+LINK32_OBJS= \
+       "$(INTDIR)\app.obj" \
+       "$(INTDIR)\condition.obj" \
+       "$(INTDIR)\dir.obj" \
+       "$(INTDIR)\DLLMain.obj" \
+       "$(INTDIR)\entropy.obj" \
+       "$(INTDIR)\errno2result.obj" \
+       "$(INTDIR)\file.obj" \
+       "$(INTDIR)\fsaccess.obj" \
+       "$(INTDIR)\interfaceiter.obj" \
+       "$(INTDIR)\ipv6.obj" \
+       "$(INTDIR)\iterated_hash.obj" \
+       "$(INTDIR)\keyboard.obj" \
+       "$(INTDIR)\net.obj" \
+       "$(INTDIR)\ntpaths.obj" \
+       "$(INTDIR)\once.obj" \
+       "$(INTDIR)\os.obj" \
+       "$(INTDIR)\resource.obj" \
+       "$(INTDIR)\socket.obj" \
+       "$(INTDIR)\stdio.obj" \
+       "$(INTDIR)\stdtime.obj" \
+       "$(INTDIR)\strerror.obj" \
+       "$(INTDIR)\syslog.obj" \
+       "$(INTDIR)\thread.obj" \
+       "$(INTDIR)\time.obj" \
+       "$(INTDIR)\version.obj" \
+       "$(INTDIR)\win32os.obj" \
+       "$(INTDIR)\assertions.obj" \
+       "$(INTDIR)\base32.obj" \
+       "$(INTDIR)\base64.obj" \
+       "$(INTDIR)\bitstring.obj" \
+       "$(INTDIR)\buffer.obj" \
+       "$(INTDIR)\bufferlist.obj" \
+       "$(INTDIR)\commandline.obj" \
+       "$(INTDIR)\error.obj" \
+       "$(INTDIR)\event.obj" \
+       "$(INTDIR)\hash.obj" \
+       "$(INTDIR)\heap.obj" \
+       "$(INTDIR)\hex.obj" \
+       "$(INTDIR)\hmacmd5.obj" \
+       "$(INTDIR)\hmacsha.obj" \
+       "$(INTDIR)\httpd.obj" \
+       "$(INTDIR)\inet_aton.obj" \
+       "$(INTDIR)\inet_ntop.obj" \
+       "$(INTDIR)\inet_pton.obj" \
+       "$(INTDIR)\lex.obj" \
+       "$(INTDIR)\lfsr.obj" \
+       "$(INTDIR)\lib.obj" \
+       "$(INTDIR)\log.obj" \
+       "$(INTDIR)\md5.obj" \
+       "$(INTDIR)\mem.obj" \
+       "$(INTDIR)\msgcat.obj" \
+       "$(INTDIR)\mutexblock.obj" \
+       "$(INTDIR)\netaddr.obj" \
+       "$(INTDIR)\netscope.obj" \
+       "$(INTDIR)\ondestroy.obj" \
+       "$(INTDIR)\quota.obj" \
+       "$(INTDIR)\radix.obj" \
+       "$(INTDIR)\random.obj" \
+       "$(INTDIR)\ratelimiter.obj" \
+       "$(INTDIR)\refcount.obj" \
+       "$(INTDIR)\result.obj" \
+       "$(INTDIR)\rwlock.obj" \
+       "$(INTDIR)\serial.obj" \
+       "$(INTDIR)\sha1.obj" \
+       "$(INTDIR)\sha2.obj" \
+       "$(INTDIR)\sockaddr.obj" \
+       "$(INTDIR)\stats.obj" \
+       "$(INTDIR)\string.obj" \
+       "$(INTDIR)\symtab.obj" \
+       "$(INTDIR)\task.obj" \
+       "$(INTDIR)\taskpool.obj" \
+       "$(INTDIR)\timer.obj" \
+       "$(INTDIR)\parseint.obj" \
+       "$(INTDIR)\portset.obj" \
+       "$(INTDIR)\region.obj"
+
+"..\..\..\Build\Release\libisc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+  $(_VC_MANIFEST_EMBED_DLL)
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+ALL : "..\..\..\Build\Debug\libisc.dll" "$(OUTDIR)\libisc.bsc"
+
+
+CLEAN :
+       -@erase "$(INTDIR)\app.obj"
+       -@erase "$(INTDIR)\app.sbr"
+       -@erase "$(INTDIR)\assertions.obj"
+       -@erase "$(INTDIR)\assertions.sbr"
+       -@erase "$(INTDIR)\base32.obj"
+       -@erase "$(INTDIR)\base32.sbr"
+       -@erase "$(INTDIR)\base64.obj"
+       -@erase "$(INTDIR)\base64.sbr"
+       -@erase "$(INTDIR)\bitstring.obj"
+       -@erase "$(INTDIR)\bitstring.sbr"
+       -@erase "$(INTDIR)\buffer.obj"
+       -@erase "$(INTDIR)\buffer.sbr"
+       -@erase "$(INTDIR)\bufferlist.obj"
+       -@erase "$(INTDIR)\bufferlist.sbr"
+       -@erase "$(INTDIR)\commandline.obj"
+       -@erase "$(INTDIR)\commandline.sbr"
+       -@erase "$(INTDIR)\condition.obj"
+       -@erase "$(INTDIR)\condition.sbr"
+       -@erase "$(INTDIR)\dir.obj"
+       -@erase "$(INTDIR)\dir.sbr"
+       -@erase "$(INTDIR)\DLLMain.obj"
+       -@erase "$(INTDIR)\DLLMain.sbr"
+       -@erase "$(INTDIR)\entropy.obj"
+       -@erase "$(INTDIR)\entropy.sbr"
+       -@erase "$(INTDIR)\errno2result.obj"
+       -@erase "$(INTDIR)\errno2result.sbr"
+       -@erase "$(INTDIR)\error.obj"
+       -@erase "$(INTDIR)\error.sbr"
+       -@erase "$(INTDIR)\event.obj"
+       -@erase "$(INTDIR)\event.sbr"
+       -@erase "$(INTDIR)\file.obj"
+       -@erase "$(INTDIR)\file.sbr"
+       -@erase "$(INTDIR)\fsaccess.obj"
+       -@erase "$(INTDIR)\fsaccess.sbr"
+       -@erase "$(INTDIR)\hash.obj"
+       -@erase "$(INTDIR)\hash.sbr"
+       -@erase "$(INTDIR)\heap.obj"
+       -@erase "$(INTDIR)\heap.sbr"
+       -@erase "$(INTDIR)\hex.obj"
+       -@erase "$(INTDIR)\hex.sbr"
+       -@erase "$(INTDIR)\hmacmd5.obj"
+       -@erase "$(INTDIR)\hmacmd5.sbr"
+       -@erase "$(INTDIR)\hmacsha.obj"
+       -@erase "$(INTDIR)\hmacsha.sbr"
+       -@erase "$(INTDIR)\httpd.obj"
+       -@erase "$(INTDIR)\httpd.sbr"
+       -@erase "$(INTDIR)\inet_aton.obj"
+       -@erase "$(INTDIR)\inet_aton.sbr"
+       -@erase "$(INTDIR)\inet_ntop.obj"
+       -@erase "$(INTDIR)\inet_ntop.sbr"
+       -@erase "$(INTDIR)\inet_pton.obj"
+       -@erase "$(INTDIR)\inet_pton.sbr"
+       -@erase "$(INTDIR)\interfaceiter.obj"
+       -@erase "$(INTDIR)\interfaceiter.sbr"
+       -@erase "$(INTDIR)\ipv6.obj"
+       -@erase "$(INTDIR)\ipv6.sbr"
+       -@erase "$(INTDIR)\iterated_hash.obj"
+       -@erase "$(INTDIR)\iterated_hash.sbr"
+       -@erase "$(INTDIR)\keyboard.obj"
+       -@erase "$(INTDIR)\keyboard.sbr"
+       -@erase "$(INTDIR)\lex.obj"
+       -@erase "$(INTDIR)\lex.sbr"
+       -@erase "$(INTDIR)\lfsr.obj"
+       -@erase "$(INTDIR)\lfsr.sbr"
+       -@erase "$(INTDIR)\lib.obj"
+       -@erase "$(INTDIR)\lib.sbr"
+       -@erase "$(INTDIR)\log.obj"
+       -@erase "$(INTDIR)\log.sbr"
+       -@erase "$(INTDIR)\md5.obj"
+       -@erase "$(INTDIR)\md5.sbr"
+       -@erase "$(INTDIR)\mem.obj"
+       -@erase "$(INTDIR)\mem.sbr"
+       -@erase "$(INTDIR)\msgcat.obj"
+       -@erase "$(INTDIR)\msgcat.sbr"
+       -@erase "$(INTDIR)\mutexblock.obj"
+       -@erase "$(INTDIR)\mutexblock.sbr"
+       -@erase "$(INTDIR)\net.obj"
+       -@erase "$(INTDIR)\net.sbr"
+       -@erase "$(INTDIR)\netaddr.obj"
+       -@erase "$(INTDIR)\netaddr.sbr"
+       -@erase "$(INTDIR)\netscope.obj"
+       -@erase "$(INTDIR)\netscope.sbr"
+       -@erase "$(INTDIR)\ntpaths.obj"
+       -@erase "$(INTDIR)\ntpaths.sbr"
+       -@erase "$(INTDIR)\once.obj"
+       -@erase "$(INTDIR)\once.sbr"
+       -@erase "$(INTDIR)\ondestroy.obj"
+       -@erase "$(INTDIR)\ondestroy.sbr"
+       -@erase "$(INTDIR)\os.obj"
+       -@erase "$(INTDIR)\os.sbr"
+       -@erase "$(INTDIR)\parseint.obj"
+       -@erase "$(INTDIR)\parseint.sbr"
+       -@erase "$(INTDIR)\portset.obj"
+       -@erase "$(INTDIR)\portset.sbr"
+       -@erase "$(INTDIR)\quota.obj"
+       -@erase "$(INTDIR)\quota.sbr"
+       -@erase "$(INTDIR)\radix.obj"
+       -@erase "$(INTDIR)\radix.sbr"
+       -@erase "$(INTDIR)\random.obj"
+       -@erase "$(INTDIR)\random.sbr"
+       -@erase "$(INTDIR)\ratelimiter.obj"
+       -@erase "$(INTDIR)\ratelimiter.sbr"
+       -@erase "$(INTDIR)\refcount.obj"
+       -@erase "$(INTDIR)\refcount.sbr"
+       -@erase "$(INTDIR)\region.obj"
+       -@erase "$(INTDIR)\region.sbr"
+       -@erase "$(INTDIR)\resource.obj"
+       -@erase "$(INTDIR)\resource.sbr"
+       -@erase "$(INTDIR)\result.obj"
+       -@erase "$(INTDIR)\result.sbr"
+       -@erase "$(INTDIR)\rwlock.obj"
+       -@erase "$(INTDIR)\rwlock.sbr"
+       -@erase "$(INTDIR)\serial.obj"
+       -@erase "$(INTDIR)\serial.sbr"
+       -@erase "$(INTDIR)\sha1.obj"
+       -@erase "$(INTDIR)\sha1.sbr"
+       -@erase "$(INTDIR)\sha2.obj"
+       -@erase "$(INTDIR)\sha2.sbr"
+       -@erase "$(INTDIR)\sockaddr.obj"
+       -@erase "$(INTDIR)\sockaddr.sbr"
+       -@erase "$(INTDIR)\socket.obj"
+       -@erase "$(INTDIR)\socket.sbr"
+       -@erase "$(INTDIR)\stats.obj"
+       -@erase "$(INTDIR)\stats.sbr"
+       -@erase "$(INTDIR)\stdio.obj"
+       -@erase "$(INTDIR)\stdio.sbr"
+       -@erase "$(INTDIR)\stdtime.obj"
+       -@erase "$(INTDIR)\stdtime.sbr"
+       -@erase "$(INTDIR)\strerror.obj"
+       -@erase "$(INTDIR)\strerror.sbr"
+       -@erase "$(INTDIR)\string.obj"
+       -@erase "$(INTDIR)\string.sbr"
+       -@erase "$(INTDIR)\symtab.obj"
+       -@erase "$(INTDIR)\symtab.sbr"
+       -@erase "$(INTDIR)\syslog.obj"
+       -@erase "$(INTDIR)\syslog.sbr"
+       -@erase "$(INTDIR)\task.obj"
+       -@erase "$(INTDIR)\task.sbr"
+       -@erase "$(INTDIR)\taskpool.obj"
+       -@erase "$(INTDIR)\taskpool.sbr"
+       -@erase "$(INTDIR)\thread.obj"
+       -@erase "$(INTDIR)\thread.sbr"
+       -@erase "$(INTDIR)\time.obj"
+       -@erase "$(INTDIR)\time.sbr"
+       -@erase "$(INTDIR)\timer.obj"
+       -@erase "$(INTDIR)\timer.sbr"
+       -@erase "$(INTDIR)\vc60.idb"
+       -@erase "$(INTDIR)\vc60.pdb"
+       -@erase "$(INTDIR)\version.obj"
+       -@erase "$(INTDIR)\version.sbr"
+       -@erase "$(INTDIR)\win32os.obj"
+       -@erase "$(INTDIR)\win32os.sbr"
+       -@erase "$(OUTDIR)\libisc.bsc"
+       -@erase "$(OUTDIR)\libisc.exp"
+       -@erase "$(OUTDIR)\libisc.lib"
+       -@erase "$(OUTDIR)\libisc.map"
+       -@erase "$(OUTDIR)\libisc.pdb"
+       -@erase "..\..\..\Build\Debug\libisc.dll"
+       -@erase "..\..\..\Build\Debug\libisc.ilk"
+       -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../../../" /I "include" /I "../include" /I "../../../lib/isc/noatomic/include" /I "win32" /I "../../isccfg/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\libisc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c 
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisc.bsc" 
+BSC32_SBRS= \
+       "$(INTDIR)\app.sbr" \
+       "$(INTDIR)\condition.sbr" \
+       "$(INTDIR)\dir.sbr" \
+       "$(INTDIR)\DLLMain.sbr" \
+       "$(INTDIR)\entropy.sbr" \
+       "$(INTDIR)\errno2result.sbr" \
+       "$(INTDIR)\file.sbr" \
+       "$(INTDIR)\fsaccess.sbr" \
+       "$(INTDIR)\interfaceiter.sbr" \
+       "$(INTDIR)\ipv6.sbr" \
+       "$(INTDIR)\iterated_hash.sbr" \
+       "$(INTDIR)\keyboard.sbr" \
+       "$(INTDIR)\net.sbr" \
+       "$(INTDIR)\ntpaths.sbr" \
+       "$(INTDIR)\once.sbr" \
+       "$(INTDIR)\os.sbr" \
+       "$(INTDIR)\resource.sbr" \
+       "$(INTDIR)\socket.sbr" \
+       "$(INTDIR)\stdio.sbr" \
+       "$(INTDIR)\stdtime.sbr" \
+       "$(INTDIR)\strerror.sbr" \
+       "$(INTDIR)\syslog.sbr" \
+       "$(INTDIR)\thread.sbr" \
+       "$(INTDIR)\time.sbr" \
+       "$(INTDIR)\version.sbr" \
+       "$(INTDIR)\win32os.sbr" \
+       "$(INTDIR)\assertions.sbr" \
+       "$(INTDIR)\base32.sbr" \
+       "$(INTDIR)\base64.sbr" \
+       "$(INTDIR)\bitstring.sbr" \
+       "$(INTDIR)\buffer.sbr" \
+       "$(INTDIR)\bufferlist.sbr" \
+       "$(INTDIR)\commandline.sbr" \
+       "$(INTDIR)\error.sbr" \
+       "$(INTDIR)\event.sbr" \
+       "$(INTDIR)\hash.sbr" \
+       "$(INTDIR)\heap.sbr" \
+       "$(INTDIR)\hex.sbr" \
+       "$(INTDIR)\hmacmd5.sbr" \
+       "$(INTDIR)\hmacsha.sbr" \
+       "$(INTDIR)\httpd.sbr" \
+       "$(INTDIR)\inet_aton.sbr" \
+       "$(INTDIR)\inet_ntop.sbr" \
+       "$(INTDIR)\inet_pton.sbr" \
+       "$(INTDIR)\lex.sbr" \
+       "$(INTDIR)\lfsr.sbr" \
+       "$(INTDIR)\lib.sbr" \
+       "$(INTDIR)\log.sbr" \
+       "$(INTDIR)\md5.sbr" \
+       "$(INTDIR)\mem.sbr" \
+       "$(INTDIR)\msgcat.sbr" \
+       "$(INTDIR)\mutexblock.sbr" \
+       "$(INTDIR)\netaddr.sbr" \
+       "$(INTDIR)\netscope.sbr" \
+       "$(INTDIR)\ondestroy.sbr" \
+       "$(INTDIR)\quota.sbr" \
+       "$(INTDIR)\radix.sbr" \
+       "$(INTDIR)\random.sbr" \
+       "$(INTDIR)\ratelimiter.sbr" \
+       "$(INTDIR)\refcount.sbr" \
+       "$(INTDIR)\result.sbr" \
+       "$(INTDIR)\rwlock.sbr" \
+       "$(INTDIR)\serial.sbr" \
+       "$(INTDIR)\sha1.sbr" \
+       "$(INTDIR)\sha2.sbr" \
+       "$(INTDIR)\sockaddr.sbr" \
+       "$(INTDIR)\stats.sbr" \
+       "$(INTDIR)\string.sbr" \
+       "$(INTDIR)\symtab.sbr" \
+       "$(INTDIR)\task.sbr" \
+       "$(INTDIR)\taskpool.sbr" \
+       "$(INTDIR)\timer.sbr" \
+       "$(INTDIR)\parseint.sbr" \
+       "$(INTDIR)\portset.sbr" \
+       "$(INTDIR)\region.sbr"
+
+"$(OUTDIR)\libisc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+    $(BSC32) @<<
+  $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\libisc.pdb" /map:"$(INTDIR)\libisc.map" /debug /machine:I386 /def:".\libisc.def" /out:"../../../Build/Debug/libisc.dll" /implib:"$(OUTDIR)\libisc.lib" /pdbtype:sept 
+DEF_FILE= \
+       ".\libisc.def"
+LINK32_OBJS= \
+       "$(INTDIR)\app.obj" \
+       "$(INTDIR)\condition.obj" \
+       "$(INTDIR)\dir.obj" \
+       "$(INTDIR)\DLLMain.obj" \
+       "$(INTDIR)\entropy.obj" \
+       "$(INTDIR)\errno2result.obj" \
+       "$(INTDIR)\file.obj" \
+       "$(INTDIR)\fsaccess.obj" \
+       "$(INTDIR)\interfaceiter.obj" \
+       "$(INTDIR)\ipv6.obj" \
+       "$(INTDIR)\iterated_hash.obj" \
+       "$(INTDIR)\keyboard.obj" \
+       "$(INTDIR)\net.obj" \
+       "$(INTDIR)\ntpaths.obj" \
+       "$(INTDIR)\once.obj" \
+       "$(INTDIR)\os.obj" \
+       "$(INTDIR)\resource.obj" \
+       "$(INTDIR)\socket.obj" \
+       "$(INTDIR)\stdio.obj" \
+       "$(INTDIR)\stdtime.obj" \
+       "$(INTDIR)\strerror.obj" \
+       "$(INTDIR)\syslog.obj" \
+       "$(INTDIR)\thread.obj" \
+       "$(INTDIR)\time.obj" \
+       "$(INTDIR)\version.obj" \
+       "$(INTDIR)\win32os.obj" \
+       "$(INTDIR)\assertions.obj" \
+       "$(INTDIR)\base32.obj" \
+       "$(INTDIR)\base64.obj" \
+       "$(INTDIR)\bitstring.obj" \
+       "$(INTDIR)\buffer.obj" \
+       "$(INTDIR)\bufferlist.obj" \
+       "$(INTDIR)\commandline.obj" \
+       "$(INTDIR)\error.obj" \
+       "$(INTDIR)\event.obj" \
+       "$(INTDIR)\hash.obj" \
+       "$(INTDIR)\heap.obj" \
+       "$(INTDIR)\hex.obj" \
+       "$(INTDIR)\hmacmd5.obj" \
+       "$(INTDIR)\hmacsha.obj" \
+       "$(INTDIR)\httpd.obj" \
+       "$(INTDIR)\inet_aton.obj" \
+       "$(INTDIR)\inet_ntop.obj" \
+       "$(INTDIR)\inet_pton.obj" \
+       "$(INTDIR)\lex.obj" \
+       "$(INTDIR)\lfsr.obj" \
+       "$(INTDIR)\lib.obj" \
+       "$(INTDIR)\log.obj" \
+       "$(INTDIR)\md5.obj" \
+       "$(INTDIR)\mem.obj" \
+       "$(INTDIR)\msgcat.obj" \
+       "$(INTDIR)\mutexblock.obj" \
+       "$(INTDIR)\netaddr.obj" \
+       "$(INTDIR)\netscope.obj" \
+       "$(INTDIR)\ondestroy.obj" \
+       "$(INTDIR)\quota.obj" \
+       "$(INTDIR)\radix.obj" \
+       "$(INTDIR)\random.obj" \
+       "$(INTDIR)\ratelimiter.obj" \
+       "$(INTDIR)\refcount.obj" \
+       "$(INTDIR)\result.obj" \
+       "$(INTDIR)\rwlock.obj" \
+       "$(INTDIR)\serial.obj" \
+       "$(INTDIR)\sha1.obj" \
+       "$(INTDIR)\sha2.obj" \
+       "$(INTDIR)\sockaddr.obj" \
+       "$(INTDIR)\stats.obj" \
+       "$(INTDIR)\string.obj" \
+       "$(INTDIR)\symtab.obj" \
+       "$(INTDIR)\task.obj" \
+       "$(INTDIR)\taskpool.obj" \
+       "$(INTDIR)\timer.obj" \
+       "$(INTDIR)\parseint.obj" \
+       "$(INTDIR)\portset.obj" \
+       "$(INTDIR)\region.obj"
+
+"..\..\..\Build\Debug\libisc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+  $(_VC_MANIFEST_EMBED_DLL)
+
+!ENDIF 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("libisc.dep")
+!INCLUDE "libisc.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "libisc.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "libisc - Win32 Release" || "$(CFG)" == "libisc - Win32 Debug"
+SOURCE=.\app.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\app.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\app.obj"    "$(INTDIR)\app.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\condition.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\condition.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\condition.obj"      "$(INTDIR)\condition.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\dir.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\dir.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\dir.obj"    "$(INTDIR)\dir.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\DLLMain.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\DLLMain.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\DLLMain.obj"        "$(INTDIR)\DLLMain.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\entropy.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\entropy.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\entropy.obj"        "$(INTDIR)\entropy.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\errno2result.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\errno2result.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\errno2result.obj"   "$(INTDIR)\errno2result.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\file.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\file.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\file.obj"   "$(INTDIR)\file.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\fsaccess.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\fsaccess.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\fsaccess.obj"       "$(INTDIR)\fsaccess.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\interfaceiter.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\interfaceiter.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\interfaceiter.obj"  "$(INTDIR)\interfaceiter.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\ipv6.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\ipv6.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\ipv6.obj"   "$(INTDIR)\ipv6.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+
+SOURCE=.\keyboard.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\keyboard.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\keyboard.obj"       "$(INTDIR)\keyboard.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\net.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\net.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\net.obj"    "$(INTDIR)\net.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\ntpaths.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\ntpaths.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\ntpaths.obj"        "$(INTDIR)\ntpaths.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\once.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\once.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\once.obj"   "$(INTDIR)\once.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\os.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\os.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\os.obj"     "$(INTDIR)\os.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\resource.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\resource.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\resource.obj"       "$(INTDIR)\resource.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\socket.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\socket.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\socket.obj" "$(INTDIR)\socket.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\stdio.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\stdio.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\stdio.obj"  "$(INTDIR)\stdio.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\stdtime.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\stdtime.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\stdtime.obj"        "$(INTDIR)\stdtime.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\strerror.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\strerror.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\strerror.obj"       "$(INTDIR)\strerror.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\syslog.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\syslog.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\syslog.obj" "$(INTDIR)\syslog.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\thread.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\thread.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\thread.obj" "$(INTDIR)\thread.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\time.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\time.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\time.obj"   "$(INTDIR)\time.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\version.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\version.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\version.obj"        "$(INTDIR)\version.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=.\win32os.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\win32os.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\win32os.obj"        "$(INTDIR)\win32os.sbr" : $(SOURCE) "$(INTDIR)"
+
+
+!ENDIF 
+
+SOURCE=..\assertions.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\assertions.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\assertions.obj"     "$(INTDIR)\assertions.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\base32.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\base32.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\base32.obj" "$(INTDIR)\base32.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\base64.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\base64.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\base64.obj" "$(INTDIR)\base64.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\bitstring.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\bitstring.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\bitstring.obj"      "$(INTDIR)\bitstring.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\buffer.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\buffer.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\buffer.obj" "$(INTDIR)\buffer.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\bufferlist.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\bufferlist.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\bufferlist.obj"     "$(INTDIR)\bufferlist.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\commandline.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\commandline.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\commandline.obj"    "$(INTDIR)\commandline.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\error.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\error.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\error.obj"  "$(INTDIR)\error.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\event.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\event.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\event.obj"  "$(INTDIR)\event.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\hash.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\hash.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\hash.obj"   "$(INTDIR)\hash.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\heap.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\heap.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\heap.obj"   "$(INTDIR)\heap.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\hex.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\hex.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\hex.obj"    "$(INTDIR)\hex.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\hmacmd5.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\hmacmd5.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\hmacmd5.obj"        "$(INTDIR)\hmacmd5.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\hmacsha.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\hmacsha.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\hmacsha.obj"        "$(INTDIR)\hmacsha.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\httpd.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\httpd.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\httpd.obj"  "$(INTDIR)\httpd.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\inet_aton.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\inet_aton.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\inet_aton.obj"      "$(INTDIR)\inet_aton.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\inet_ntop.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\inet_ntop.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\inet_ntop.obj"      "$(INTDIR)\inet_ntop.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\inet_pton.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\inet_pton.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\inet_pton.obj"      "$(INTDIR)\inet_pton.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\iterated_hash.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\iterated_hash.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\iterated_hash.obj"  "$(INTDIR)\iterated_hash.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\lex.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\lex.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\lex.obj"    "$(INTDIR)\lex.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\lfsr.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\lfsr.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\lfsr.obj"   "$(INTDIR)\lfsr.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\lib.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\lib.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\lib.obj"    "$(INTDIR)\lib.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\log.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\log.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\log.obj"    "$(INTDIR)\log.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\md5.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\md5.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\md5.obj"    "$(INTDIR)\md5.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\mem.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\mem.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\mem.obj"    "$(INTDIR)\mem.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\nls\msgcat.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\msgcat.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\msgcat.obj" "$(INTDIR)\msgcat.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\mutexblock.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\mutexblock.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\mutexblock.obj"     "$(INTDIR)\mutexblock.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\netaddr.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\netaddr.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\netaddr.obj"        "$(INTDIR)\netaddr.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\netscope.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\netscope.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\netscope.obj"       "$(INTDIR)\netscope.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\ondestroy.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\ondestroy.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\ondestroy.obj"      "$(INTDIR)\ondestroy.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\parseint.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\parseint.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\parseint.obj"       "$(INTDIR)\parseint.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\portset.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\portset.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\portset.obj"        "$(INTDIR)\portset.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\quota.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\quota.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\quota.obj"  "$(INTDIR)\quota.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\radix.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\radix.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\radix.obj"  "$(INTDIR)\radix.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\random.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\random.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\random.obj" "$(INTDIR)\random.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\ratelimiter.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\ratelimiter.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\ratelimiter.obj"    "$(INTDIR)\ratelimiter.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\refcount.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\refcount.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\refcount.obj"       "$(INTDIR)\refcount.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\region.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\region.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\region.obj" "$(INTDIR)\region.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\result.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\result.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\result.obj" "$(INTDIR)\result.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\rwlock.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\rwlock.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\rwlock.obj" "$(INTDIR)\rwlock.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\serial.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\serial.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\serial.obj" "$(INTDIR)\serial.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\sha1.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\sha1.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\sha1.obj"   "$(INTDIR)\sha1.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\sha2.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\sha2.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\sha2.obj"   "$(INTDIR)\sha2.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\sockaddr.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\sockaddr.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\sockaddr.obj"       "$(INTDIR)\sockaddr.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\stats.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\stats.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\stats.obj"  "$(INTDIR)\stats.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\string.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\string.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\string.obj" "$(INTDIR)\string.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\symtab.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\symtab.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\symtab.obj" "$(INTDIR)\symtab.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\task.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\task.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\task.obj"   "$(INTDIR)\task.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\taskpool.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\taskpool.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\taskpool.obj"       "$(INTDIR)\taskpool.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+SOURCE=..\timer.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\timer.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\timer.obj"  "$(INTDIR)\timer.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF 
+
+
+!ENDIF 
+
+####################################################
+# Commands to generate initial empty manifest file and the RC file
+# that references it, and for generating the .res file:
+
+$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc
+
+$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest
+    type <<$@
+#include <winuser.h>
+1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest"
+<< KEEP
+
+$(_VC_MANIFEST_BASENAME).auto.manifest :
+    type <<$@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+</assembly>
+<< KEEP
index e7237bbf2bfd81e09e525f7f2fafed1bf5572c58..3785f8abdf1b08f68ea1ba86524f4bb1e8ff3121 100644 (file)
@@ -61,10 +61,10 @@ static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
 
 void InitSockets(void);
 
-
 static isc_result_t
 try_proto(int domain) {
        SOCKET s;
+       isc_result_t result = ISC_R_SUCCESS;
        char strbuf[ISC_STRERRORSIZE];
        int errval;
 
@@ -166,7 +166,7 @@ try_ipv6only(void) {
        }
 
        on = 1;
-       if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) {
+       if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
                ipv6only_result = ISC_R_NOTFOUND;
                goto close;
        }
@@ -189,7 +189,7 @@ try_ipv6only(void) {
        }
 
        on = 1;
-       if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) {
+       if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
                ipv6only_result = ISC_R_NOTFOUND;
                goto close;
        }
@@ -197,7 +197,7 @@ try_ipv6only(void) {
        ipv6only_result = ISC_R_SUCCESS;
 
 close:
-       closesocket(s);
+       closeocket(s);
        return;
 #endif /* IPV6_V6ONLY */
 }
diff --git a/lib/isc/win32/netdb.h b/lib/isc/win32/netdb.h
new file mode 100644 (file)
index 0000000..fa94180
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2004, 2006, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: netdb.h,v 1.7.332.2 2009/01/18 23:47:41 tbox Exp $ */
+
+#ifndef NETDB_H
+#define NETDB_H 1
+
+#include <stddef.h>
+#include <winsock2.h>
+
+/*
+ * Define if <netdb.h> does not declare struct addrinfo.
+ */
+
+struct addrinfo {
+       int             ai_flags;      /* AI_PASSIVE, AI_CANONNAME */
+       int             ai_family;     /* PF_xxx */
+       int             ai_socktype;   /* SOCK_xxx */
+       int             ai_protocol;   /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+       size_t          ai_addrlen;    /* Length of ai_addr */
+       char            *ai_canonname; /* Canonical name for hostname */
+       struct sockaddr *ai_addr;      /* Binary address */
+       struct addrinfo *ai_next;      /* Next structure in linked list */
+};
+
+
+/*
+ * Undefine all \#defines we are interested in as <netdb.h> may or may not have
+ * defined them.
+ */
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#undef NETDB_INTERNAL
+#undef NETDB_SUCCESS
+#undef HOST_NOT_FOUND
+#undef TRY_AGAIN
+#undef NO_RECOVERY
+#undef NO_DATA
+#undef NO_ADDRESS
+
+#define        NETDB_INTERNAL  -1      /* see errno */
+#define        NETDB_SUCCESS   0       /* no problem */
+#define        HOST_NOT_FOUND  1 /* Authoritative Answer Host not found */
+#define        TRY_AGAIN       2 /* Non-Authoritative Host not found, or SERVERFAIL */
+#define        NO_RECOVERY     3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define        NO_DATA         4 /* Valid name, no data record of requested type */
+#define        NO_ADDRESS      NO_DATA         /* no address, look for MX record */
+
+/*
+ * Error return codes from getaddrinfo()
+ */
+
+#undef EAI_ADDRFAMILY
+#undef EAI_AGAIN
+#undef EAI_BADFLAGS
+#undef EAI_FAIL
+#undef EAI_FAMILY
+#undef EAI_MEMORY
+#undef EAI_NODATA
+#undef EAI_NONAME
+#undef EAI_SERVICE
+#undef EAI_SOCKTYPE
+#undef EAI_SYSTEM
+#undef EAI_BADHINTS
+#undef EAI_PROTOCOL
+#undef EAI_MAX
+
+#define        EAI_ADDRFAMILY   1      /* address family for hostname not supported */
+#define        EAI_AGAIN        2      /* temporary failure in name resolution */
+#define        EAI_BADFLAGS     3      /* invalid value for ai_flags */
+#define        EAI_FAIL         4      /* non-recoverable failure in name resolution */
+#define        EAI_FAMILY       5      /* ai_family not supported */
+#define        EAI_MEMORY       6      /* memory allocation failure */
+#define        EAI_NODATA       7      /* no address associated with hostname */
+#define        EAI_NONAME       8      /* hostname nor servname provided, or not known */
+#define        EAI_SERVICE      9      /* servname not supported for ai_socktype */
+#define        EAI_SOCKTYPE    10      /* ai_socktype not supported */
+#define        EAI_SYSTEM      11      /* system error returned in errno */
+#define EAI_BADHINTS   12
+#define EAI_PROTOCOL   13
+#define EAI_MAX                14
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#undef AI_PASSIVE
+#undef AI_CANONNAME
+#undef AI_NUMERICHOST
+
+#define        AI_PASSIVE      0x00000001
+#define        AI_CANONNAME    0x00000002
+#define AI_NUMERICHOST 0x00000004
+
+/*
+ * Flag values for getipnodebyname()
+ */
+#undef AI_V4MAPPED
+#undef AI_ALL
+#undef AI_ADDRCONFIG
+#undef AI_DEFAULT
+
+#define AI_V4MAPPED    0x00000008
+#define AI_ALL         0x00000010
+#define AI_ADDRCONFIG  0x00000020
+#define AI_DEFAULT     (AI_V4MAPPED|AI_ADDRCONFIG)
+
+/*
+ * Constants for getnameinfo()
+ */
+#undef NI_MAXHOST
+#undef NI_MAXSERV
+
+#define        NI_MAXHOST      1025
+#define        NI_MAXSERV      32
+
+/*
+ * Flag values for getnameinfo()
+ */
+#undef NI_NOFQDN
+#undef NI_NUMERICHOST
+#undef NI_NAMEREQD
+#undef NI_NUMERICSERV
+#undef NI_DGRAM
+#undef NI_NUMERICSCOPE
+
+#define        NI_NOFQDN       0x00000001
+#define        NI_NUMERICHOST  0x00000002
+#define        NI_NAMEREQD     0x00000004
+#define        NI_NUMERICSERV  0x00000008
+#define        NI_DGRAM        0x00000010
+#define        NI_NUMERICSCOPE 0x00000020      /*2553bis-00*/
+
+/*
+ * Structures for getrrsetbyname()
+ */
+struct rdatainfo {
+       unsigned int            rdi_length;
+       unsigned char           *rdi_data;
+};
+
+struct rrsetinfo {
+       unsigned int            rri_flags;
+       int                     rri_rdclass;
+       int                     rri_rdtype;
+       unsigned int            rri_ttl;
+       unsigned int            rri_nrdatas;
+       unsigned int            rri_nsigs;
+       char                    *rri_name;
+       struct rdatainfo        *rri_rdatas;
+       struct rdatainfo        *rri_sigs;
+};
+
+/*
+ * Flags for getrrsetbyname()
+ */
+#define RRSET_VALIDATED                0x00000001
+       /* Set was dnssec validated */
+
+/*
+ * Return codes for getrrsetbyname()
+ */
+#define ERRSET_SUCCESS         0
+#define ERRSET_NOMEMORY                1
+#define ERRSET_FAIL            2
+#define ERRSET_INVAL           3
+
+
+#endif /* NETDB_H */
diff --git a/lib/isc/win32/ntgroups.c b/lib/isc/win32/ntgroups.c
new file mode 100644 (file)
index 0000000..351adc5
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2004, 2006, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ntgroups.c,v 1.10 2007/06/19 23:47:19 tbox Exp $ */
+
+/*
+ * The NT Groups have two groups that are not well documented and are
+ * not normally seen: None and Everyone.  A user account belongs to
+ * any number of groups, but if it is not a member of any group then
+ * it is a member of the None Group. The None group is not listed
+ * anywhere. You cannot remove an account from the none group except
+ * by making it a member of some other group, The second group is the
+ * Everyone group.  All accounts, no matter how many groups that they
+ * belong to, also belong to the Everyone group. You cannot remove an
+ * account from the Everyone group.
+ */
+
+#ifndef UNICODE
+#define UNICODE
+#endif /* UNICODE */
+
+/*
+ * Silence warnings.
+ */
+#define _CRT_SECURE_NO_DEPRECATE 1
+
+#include <windows.h>
+#include <assert.h>
+#include <lm.h>
+
+#include <isc/ntgroups.h>
+#include <isc/result.h>
+
+#define MAX_NAME_LENGTH 256
+
+isc_result_t
+isc_ntsecurity_getaccountgroups(char *username, char **GroupList,
+                               unsigned int maxgroups,
+                               unsigned int *totalGroups) {
+       LPGROUP_USERS_INFO_0 pTmpBuf;
+       LPLOCALGROUP_USERS_INFO_0 pTmpLBuf;
+       DWORD i;
+       LPLOCALGROUP_USERS_INFO_0 pBuf = NULL;
+       LPGROUP_USERS_INFO_0 pgrpBuf = NULL;
+       DWORD dwLevel = 0;
+       DWORD dwFlags = LG_INCLUDE_INDIRECT;
+       DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
+       DWORD dwEntriesRead = 0;
+       DWORD dwTotalEntries = 0;
+       NET_API_STATUS nStatus;
+       DWORD dwTotalCount = 0;
+       int retlen;
+       wchar_t user[MAX_NAME_LENGTH];
+
+       retlen = mbstowcs(user, username, MAX_NAME_LENGTH);
+
+       *totalGroups = 0;
+       /*
+        * Call the NetUserGetLocalGroups function 
+        * specifying information level 0.
+        *
+        * The LG_INCLUDE_INDIRECT flag specifies that the 
+        * function should also return the names of the local 
+        * groups in which the user is indirectly a member.
+        */
+       nStatus = NetUserGetLocalGroups(NULL,
+                                   user,
+                                   dwLevel,
+                                   dwFlags,
+                                   (LPBYTE *) &pBuf,
+                                   dwPrefMaxLen,
+                                   &dwEntriesRead,
+                                   &dwTotalEntries);
+       /*
+        * See if the call succeeds,
+        */
+       if (nStatus != NERR_Success) {
+               if (nStatus == ERROR_ACCESS_DENIED)
+                       return (ISC_R_NOPERM);
+               if (nStatus == ERROR_MORE_DATA)
+                       return (ISC_R_NOSPACE);
+               if (nStatus == NERR_UserNotFound)
+                       dwEntriesRead = 0;
+       }
+
+       dwTotalCount = 0;
+       if (pBuf != NULL) {
+               pTmpLBuf = pBuf;
+               /*
+                * Loop through the entries
+                */
+                for (i = 0;
+                    (i < dwEntriesRead && *totalGroups < maxgroups); i++) {
+                       assert(pTmpLBuf != NULL);
+                       if (pTmpLBuf == NULL)
+                               break;
+                       retlen = wcslen(pTmpLBuf->lgrui0_name);
+                       GroupList[*totalGroups] = (char *) malloc(retlen +1);
+                       if (GroupList[*totalGroups] == NULL)
+                               return (ISC_R_NOMEMORY);
+
+                       retlen = wcstombs(GroupList[*totalGroups],
+                                pTmpLBuf->lgrui0_name, retlen);
+                       GroupList[*totalGroups][retlen] = '\0';
+                       if (strcmp(GroupList[*totalGroups], "None") == 0)
+                               free(GroupList[*totalGroups]);
+                       else
+                               (*totalGroups)++;
+                       pTmpLBuf++;
+               }
+       }
+       /* Free the allocated memory. */
+       if (pBuf != NULL)
+               NetApiBufferFree(pBuf);
+
+   
+       /*
+        * Call the NetUserGetGroups function, specifying level 0.
+        */
+       nStatus = NetUserGetGroups(NULL,
+                              user,
+                              dwLevel,
+                              (LPBYTE*)&pgrpBuf,
+                              dwPrefMaxLen,
+                              &dwEntriesRead,
+                              &dwTotalEntries);
+       /*
+        * See if the call succeeds,
+        */
+       if (nStatus != NERR_Success) {
+               if (nStatus == ERROR_ACCESS_DENIED)
+                       return (ISC_R_NOPERM);
+               if (nStatus == ERROR_MORE_DATA)
+                       return (ISC_R_NOSPACE);
+               if (nStatus == NERR_UserNotFound)
+                       dwEntriesRead = 0;
+       }
+       if (pgrpBuf != NULL) {
+               pTmpBuf = pgrpBuf;
+               /*
+                * Loop through the entries
+                */
+                for (i = 0;
+                    (i < dwEntriesRead && *totalGroups < maxgroups); i++) {
+                       assert(pTmpBuf != NULL);
+
+                       if (pTmpBuf == NULL)
+                               break;
+                       retlen = wcslen(pTmpBuf->grui0_name);
+                       GroupList[*totalGroups] = (char *) malloc(retlen +1);
+                       if (GroupList[*totalGroups] == NULL)
+                               return (ISC_R_NOMEMORY);
+
+                       retlen = wcstombs(GroupList[*totalGroups],
+                                pTmpBuf->grui0_name, retlen);
+                       GroupList[*totalGroups][retlen] = '\0';
+                       if (strcmp(GroupList[*totalGroups], "None") == 0)
+                               free(GroupList[*totalGroups]);
+                       else
+                               (*totalGroups)++;
+                       pTmpBuf++;
+               }
+       }
+       /*
+        * Free the allocated memory.
+        */
+       if (pgrpBuf != NULL)
+               NetApiBufferFree(pgrpBuf);
+
+       return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/win32/ntpaths.c b/lib/isc/win32/ntpaths.c
new file mode 100644 (file)
index 0000000..d1c622f
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: ntpaths.c,v 1.11 2007/06/18 23:47:49 tbox Exp $ */
+
+/*
+ * This module fetches the required path information that is specific
+ * to NT systems which can have its configuration and system files
+ * almost anywhere. It can be used to override whatever the application
+ * had previously assigned to the pointer. Basic information about the
+ * file locations are stored in the registry.
+ */
+
+#include <config.h>
+#include <isc/bind_registry.h>
+#include <isc/ntpaths.h>
+
+/*
+ * Module Variables
+ */
+
+static char systemDir[MAX_PATH];
+static char namedBase[MAX_PATH];
+static char ns_confFile[MAX_PATH];
+static char lwresd_confFile[MAX_PATH];
+static char lwresd_resolvconfFile[MAX_PATH];
+static char rndc_confFile[MAX_PATH];
+static char ns_defaultpidfile[MAX_PATH];
+static char lwresd_defaultpidfile[MAX_PATH];
+static char local_state_dir[MAX_PATH];
+static char sys_conf_dir[MAX_PATH];
+static char rndc_keyFile[MAX_PATH];
+
+static DWORD baseLen = MAX_PATH;
+static BOOL Initialized = FALSE;
+
+void
+isc_ntpaths_init() {
+       HKEY hKey;
+       BOOL keyFound = TRUE;
+
+       memset(namedBase, 0, MAX_PATH);
+       if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SUBKEY, 0, KEY_READ, &hKey)
+               != ERROR_SUCCESS)
+               keyFound = FALSE;
+       
+       if (keyFound == TRUE) {
+               /* Get the named directory */
+               if (RegQueryValueEx(hKey, "InstallDir", NULL, NULL,
+                       (LPBYTE)namedBase, &baseLen) != ERROR_SUCCESS)
+                       keyFound = FALSE;
+               RegCloseKey(hKey);
+       }
+
+       GetSystemDirectory(systemDir, MAX_PATH);
+
+       if (keyFound == FALSE)
+               /* Use the System Directory as a default */
+               strcpy(namedBase, systemDir);
+
+       strcpy(ns_confFile, namedBase);
+       strcat(ns_confFile, "\\etc\\named.conf");
+
+       strcpy(lwresd_confFile, namedBase);
+       strcat(lwresd_confFile, "\\etc\\lwresd.conf");
+
+       strcpy(lwresd_resolvconfFile, systemDir);
+       strcat(lwresd_resolvconfFile, "\\Drivers\\etc\\resolv.conf");
+
+       strcpy(rndc_keyFile, namedBase);
+       strcat(rndc_keyFile, "\\etc\\rndc.key");
+
+       strcpy(rndc_confFile, namedBase);
+       strcat(rndc_confFile, "\\etc\\rndc.conf");
+       strcpy(ns_defaultpidfile, namedBase);
+       strcat(ns_defaultpidfile, "\\etc\\named.pid");
+
+       strcpy(lwresd_defaultpidfile, namedBase);
+       strcat(lwresd_defaultpidfile, "\\etc\\lwresd.pid");
+
+       strcpy(local_state_dir, namedBase);
+       strcat(local_state_dir, "\\bin");
+
+       strcpy(sys_conf_dir, namedBase);
+       strcat(sys_conf_dir, "\\etc");
+       
+       Initialized = TRUE;
+}
+
+char *
+isc_ntpaths_get(int ind) {
+       if (!Initialized)
+               isc_ntpaths_init();
+
+       switch (ind) {
+       case NAMED_CONF_PATH:
+               return (ns_confFile);
+               break;
+       case LWRES_CONF_PATH:
+               return (lwresd_confFile);
+               break;
+       case RESOLV_CONF_PATH:
+               return (lwresd_resolvconfFile);
+               break;
+       case RNDC_CONF_PATH:
+               return (rndc_confFile);
+               break;
+       case NAMED_PID_PATH:
+               return (ns_defaultpidfile);
+               break;
+       case LWRESD_PID_PATH:
+               return (lwresd_defaultpidfile);
+               break;
+       case LOCAL_STATE_DIR:
+               return (local_state_dir);
+               break;
+       case SYS_CONF_DIR:
+               return (sys_conf_dir);
+               break;
+       case RNDC_KEY_PATH:
+               return (rndc_keyFile);
+               break;
+       default:
+               return (NULL);
+       }
+}
index 846f037bcae169d988d4d3f8ef3662e3da50cf81..b5047762ad77bae48a7d28983a924db61b81bd17 100644 (file)
@@ -1,21 +1,21 @@
 /*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1999-2001  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: once.c,v 1.9 2001/07/09 21:06:16 gson Exp $ */
+/* $Id: once.c,v 1.12 2007/06/18 23:47:49 tbox Exp $ */
 
 /* Principal Authors: DCL */
 
@@ -33,7 +33,7 @@ isc_once_do(isc_once_t *controller, void(*function)(void)) {
 
        if (controller->status == ISC_ONCE_INIT_NEEDED) {
 
-               if (InterlockedDecrement((long *)&controller->counter) == 0) {
+               if (InterlockedDecrement(&controller->counter) == 0) {
                        if (controller->status == ISC_ONCE_INIT_NEEDED) {
                                function();
                                controller->status = ISC_ONCE_INIT_DONE;
@@ -41,8 +41,11 @@ isc_once_do(isc_once_t *controller, void(*function)(void)) {
                } else {
                        while (controller->status == ISC_ONCE_INIT_NEEDED) {
                                /*
-                                * Spin wait.
+                                * Sleep(0) indicates that this thread 
+                                * should be suspended to allow other 
+                                * waiting threads to execute.
                                 */
+                               Sleep(0);
                        }
                }
        }
diff --git a/lib/isc/win32/os.c b/lib/isc/win32/os.c
new file mode 100644 (file)
index 0000000..bbd5f1d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: os.c,v 1.8 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <windows.h>
+
+#include <isc/os.h>
+
+static BOOL bInit = FALSE;
+static SYSTEM_INFO SystemInfo;
+
+static void
+initialize_action(void) {
+       if (bInit)
+               return;
+       
+       GetSystemInfo(&SystemInfo);
+       bInit = TRUE;
+}
+
+unsigned int
+isc_os_ncpus(void) {
+       long ncpus = 1;
+       initialize_action();
+       ncpus = SystemInfo.dwNumberOfProcessors;
+       if (ncpus <= 0)
+               ncpus = 1;
+
+       return ((unsigned int)ncpus);
+}
diff --git a/lib/isc/win32/resource.c b/lib/isc/win32/resource.c
new file mode 100644 (file)
index 0000000..e7e7cf4
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2004, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: resource.c,v 1.10 2008/07/11 23:47:09 tbox Exp $ */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <isc/platform.h>
+#include <isc/resource.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+/*
+ * Windows limits the maximum number of open files to 2048
+ */
+
+#define WIN32_MAX_OPEN_FILES   2048
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
+       isc_resourcevalue_t rlim_value;
+       int wresult;
+
+       if (resource != isc_resource_openfiles)
+               return (ISC_R_NOTIMPLEMENTED);
+
+
+       if (value == ISC_RESOURCE_UNLIMITED)
+               rlim_value = WIN32_MAX_OPEN_FILES;
+       else
+               rlim_value = min(value, WIN32_MAX_OPEN_FILES);
+
+       wresult = _setmaxstdio((int) rlim_value);
+
+       if (wresult > 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+
+       if (resource != isc_resource_openfiles)
+               return (ISC_R_NOTIMPLEMENTED);
+
+       *value = WIN32_MAX_OPEN_FILES;
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+       return (isc_resource_getlimit(resource, value));
+}
diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c
new file mode 100644 (file)
index 0000000..7c4068f
--- /dev/null
@@ -0,0 +1,3674 @@
+/*
+ * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: socket.c,v 1.70.54.4 2009/01/29 22:40:36 jinmei Exp $ */
+
+/* This code uses functions which are only available on Server 2003 and
+ * higher, and Windows XP and higher.
+ *
+ * This code is by nature multithreaded and takes advantage of various
+ * features to pass on information through the completion port for
+ * when I/O is completed.  All sends, receives, accepts, and connects are
+ * completed through the completion port.
+ *
+ * The number of Completion Port Worker threads used is the total number
+ * of CPU's + 1. This increases the likelihood that a Worker Thread is
+ * available for processing a completed request.
+ *
+ * XXXPDM 5 August, 2002
+ */
+
+#define MAKE_EXTERNAL 1
+#include <config.h>
+
+#include <sys/types.h>
+
+#ifndef _WINSOCKAPI_
+#define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
+#endif
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <io.h>
+#include <fcntl.h>
+#include <process.h>
+
+#include <isc/buffer.h>
+#include <isc/bufferlist.h>
+#include <isc/condition.h>
+#include <isc/list.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/msgs.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/once.h>
+#include <isc/os.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/region.h>
+#include <isc/socket.h>
+#include <isc/stats.h>
+#include <isc/strerror.h>
+#include <isc/syslog.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+#include <isc/win32os.h>
+
+#include <mswsock.h>
+
+#include "errno2result.h"
+
+/*
+ * How in the world can Microsoft exist with APIs like this?
+ * We can't actually call this directly, because it turns out
+ * no library exports this function.  Instead, we need to
+ * issue a runtime call to get the address.
+ */
+LPFN_CONNECTEX ISCConnectEx;
+LPFN_ACCEPTEX ISCAcceptEx;
+LPFN_GETACCEPTEXSOCKADDRS ISCGetAcceptExSockaddrs;
+
+/*
+ * Run expensive internal consistency checks.
+ */
+#ifdef ISC_SOCKET_CONSISTENCY_CHECKS
+#define CONSISTENT(sock) consistent(sock)
+#else
+#define CONSISTENT(sock) do {} while (0)
+#endif
+static void consistent(isc_socket_t *sock);
+
+/*
+ * Define this macro to control the behavior of connection
+ * resets on UDP sockets.  See Microsoft KnowledgeBase Article Q263823
+ * for details.
+ * NOTE: This requires that Windows 2000 systems install Service Pack 2
+ * or later.
+ */
+#ifndef SIO_UDP_CONNRESET
+#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
+#endif
+
+/*
+ * Some systems define the socket length argument as an int, some as size_t,
+ * some as socklen_t.  This is here so it can be easily changed if needed.
+ */
+#ifndef ISC_SOCKADDR_LEN_T
+#define ISC_SOCKADDR_LEN_T unsigned int
+#endif
+
+/*
+ * Define what the possible "soft" errors can be.  These are non-fatal returns
+ * of various network related functions, like recv() and so on.
+ */
+#define SOFT_ERROR(e)  ((e) == WSAEINTR || \
+                        (e) == WSAEWOULDBLOCK || \
+                        (e) == EWOULDBLOCK || \
+                        (e) == EINTR || \
+                        (e) == EAGAIN || \
+                        (e) == 0)
+
+/*
+ * Pending errors are not really errors and should be
+ * kept separate
+ */
+#define PENDING_ERROR(e) ((e) == WSA_IO_PENDING || (e) == 0)
+
+#define DOIO_SUCCESS     0       /* i/o ok, event sent */
+#define DOIO_SOFT        1       /* i/o ok, soft error, no event sent */
+#define DOIO_HARD        2       /* i/o error, event sent */
+#define DOIO_EOF         3       /* EOF, no event sent */
+#define DOIO_PENDING     4       /* status when i/o is in process */
+#define DOIO_NEEDMORE    5       /* IO was processed, but we need more due to minimum */
+
+#define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x)
+
+/*
+ * DLVL(90)  --  Function entry/exit and other tracing.
+ * DLVL(70)  --  Socket "correctness" -- including returning of events, etc.
+ * DLVL(60)  --  Socket data send/receive
+ * DLVL(50)  --  Event tracing, including receiving/sending completion events.
+ * DLVL(20)  --  Socket creation/destruction.
+ */
+#define TRACE_LEVEL            90
+#define CORRECTNESS_LEVEL      70
+#define IOEVENT_LEVEL          60
+#define EVENT_LEVEL            50
+#define CREATION_LEVEL         20
+
+#define TRACE          DLVL(TRACE_LEVEL)
+#define CORRECTNESS    DLVL(CORRECTNESS_LEVEL)
+#define IOEVENT                DLVL(IOEVENT_LEVEL)
+#define EVENT          DLVL(EVENT_LEVEL)
+#define CREATION       DLVL(CREATION_LEVEL)
+
+typedef isc_event_t intev_t;
+
+/*
+ * Socket State
+ */
+enum {
+  SOCK_INITIALIZED,    /* Socket Initialized */
+  SOCK_OPEN,           /* Socket opened but nothing yet to do */
+  SOCK_DATA,           /* Socket sending or receiving data */
+  SOCK_LISTEN,         /* TCP Socket listening for connects */
+  SOCK_ACCEPT,         /* TCP socket is waiting to accept */
+  SOCK_CONNECT,                /* TCP Socket connecting */
+  SOCK_CLOSED,         /* Socket has been closed */
+};
+
+#define SOCKET_MAGIC           ISC_MAGIC('I', 'O', 'i', 'o')
+#define VALID_SOCKET(t)                ISC_MAGIC_VALID(t, SOCKET_MAGIC)
+
+/*
+ * IPv6 control information.  If the socket is an IPv6 socket we want
+ * to collect the destination address and interface so the client can
+ * set them on outgoing packets.
+ */
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifndef USE_CMSG
+#define USE_CMSG       1
+#endif
+#endif
+
+/*
+ * We really  don't want to try and use these control messages. Win32
+ * doesn't have this mechanism before XP.
+ */
+#undef USE_CMSG
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ * Used value-result for recvmsg, value only for sendmsg.
+ */
+struct msghdr {
+       SOCKADDR_STORAGE to_addr;       /* UDP send/recv address */
+       int      to_addr_len;           /* length of the address */
+       WSABUF  *msg_iov;               /* scatter/gather array */
+       u_int   msg_iovlen;             /* # elements in msg_iov */
+       void    *msg_control;           /* ancillary data, see below */
+       u_int   msg_controllen;         /* ancillary data buffer len */
+       int     msg_totallen;           /* total length of this message */
+} msghdr;
+
+/*
+ * The size to raise the receive buffer to.
+ */
+#define RCVBUFSIZE (32*1024)
+
+/*
+ * The number of times a send operation is repeated if the result
+ * is WSAEINTR.
+ */
+#define NRETRIES 10
+
+struct isc_socket {
+       /* Not locked. */
+       unsigned int            magic;
+       isc_socketmgr_t        *manager;
+       isc_mutex_t             lock;
+       isc_sockettype_t        type;
+
+       /* Pointers to scatter/gather buffers */
+       WSABUF                  iov[ISC_SOCKET_MAXSCATTERGATHER];
+
+       /* Locked by socket lock. */
+       ISC_LINK(isc_socket_t)  link;
+       unsigned int            references; /* EXTERNAL references */
+       SOCKET                  fd;     /* file handle */
+       int                     pf;     /* protocol family */
+       char                    name[16];
+       void *                  tag;
+
+       /*
+        * Each recv() call uses this buffer.  It is a per-socket receive
+        * buffer that allows us to decouple the system recv() from the
+        * recv_list done events.  This means the items on the recv_list
+        * can be removed without having to cancel pending system recv()
+        * calls.  It also allows us to read-ahead in some cases.
+        */
+       struct {
+               SOCKADDR_STORAGE        from_addr;         // UDP send/recv address
+               int             from_addr_len;     // length of the address
+               char            *base;             // the base of the buffer
+               char            *consume_position; // where to start copying data from next
+               unsigned int    len;               // the actual size of this buffer
+               unsigned int    remaining;         // the number of bytes remaining
+       } recvbuf;
+
+       ISC_LIST(isc_socketevent_t)             send_list;
+       ISC_LIST(isc_socketevent_t)             recv_list;
+       ISC_LIST(isc_socket_newconnev_t)        accept_list;
+       isc_socket_connev_t                    *connect_ev;
+
+       isc_sockaddr_t          address;  /* remote address */
+
+       unsigned int            listener : 1,   /* listener socket */
+                               connected : 1,
+                               pending_connect : 1, /* connect pending */
+                               bound : 1;      /* bound to local addr */
+       unsigned int            pending_iocp;   /* Should equal the counters below. Debug. */
+       unsigned int            pending_recv;  /* Number of outstanding recv() calls. */
+       unsigned int            pending_send;  /* Number of outstanding send() calls. */
+       unsigned int            pending_accept; /* Number of outstanding accept() calls. */
+       unsigned int            state; /* Socket state. Debugging and consistency checking. */
+       int                     state_lineno;  /* line which last touched state */
+};
+
+#define _set_state(sock, _state) do { (sock)->state = (_state); (sock)->state_lineno = __LINE__; } while (0)
+
+/*
+ * Buffer structure
+ */
+typedef struct buflist buflist_t;
+
+struct buflist {
+       void                    *buf;
+       unsigned int            buflen;
+       ISC_LINK(buflist_t)     link;
+};
+
+/*
+ * I/O Completion ports Info structures
+ */
+
+static HANDLE hHeapHandle = NULL;
+typedef struct IoCompletionInfo {
+       OVERLAPPED              overlapped;
+       isc_socketevent_t       *dev;  /* send()/recv() done event */
+       isc_socket_connev_t     *cdev; /* connect() done event */
+       isc_socket_newconnev_t  *adev; /* accept() done event */
+       void                    *acceptbuffer;
+       DWORD                   received_bytes;
+       int                     request_type;
+       struct msghdr           messagehdr;
+       ISC_LIST(buflist_t)     bufferlist;     /*%< list of buffers */
+} IoCompletionInfo;
+
+/*
+ * Define a maximum number of I/O Completion Port worker threads
+ * to handle the load on the Completion Port. The actual number
+ * used is the number of CPU's + 1.
+ */
+#define MAX_IOCPTHREADS 20
+
+#define SOCKET_MANAGER_MAGIC   ISC_MAGIC('I', 'O', 'm', 'g')
+#define VALID_MANAGER(m)       ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
+
+struct isc_socketmgr {
+       /* Not locked. */
+       unsigned int                    magic;
+       isc_mem_t                      *mctx;
+       isc_mutex_t                     lock;
+       isc_stats_t                    *stats;
+
+       /* Locked by manager lock. */
+       ISC_LIST(isc_socket_t)          socklist;
+       isc_boolean_t                   bShutdown;
+       isc_condition_t                 shutdown_ok;
+       HANDLE                          hIoCompletionPort;
+       int                             maxIOCPThreads;
+       HANDLE                          hIOCPThreads[MAX_IOCPTHREADS];
+       DWORD                           dwIOCPThreadIds[MAX_IOCPTHREADS];
+
+       /*
+        * Debugging.
+        * Modified by InterlockedIncrement() and InterlockedDecrement()
+        */
+       LONG                            totalSockets;
+       LONG                            iocp_total;
+};
+
+enum {
+       SOCKET_RECV,
+       SOCKET_SEND,
+       SOCKET_ACCEPT,
+       SOCKET_CONNECT
+};
+
+/*
+ * send() and recv() iovec counts
+ */
+#define MAXSCATTERGATHER_SEND  (ISC_SOCKET_MAXSCATTERGATHER)
+#define MAXSCATTERGATHER_RECV  (ISC_SOCKET_MAXSCATTERGATHER)
+
+static isc_threadresult_t WINAPI SocketIoThread(LPVOID ThreadContext);
+static void maybe_free_socket(isc_socket_t **, int);
+static void free_socket(isc_socket_t **, int);
+static isc_boolean_t senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev);
+static isc_boolean_t acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev);
+static isc_boolean_t connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev);
+static void send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev);
+static void send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev);
+static void send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev);
+static void send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev);
+static void send_recvdone_abort(isc_socket_t *sock, isc_result_t result);
+static void queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev);
+static void queue_receive_request(isc_socket_t *sock);
+
+/*
+ * This is used to dump the contents of the sock structure
+ * You should make sure that the sock is locked before
+ * dumping it. Since the code uses simple printf() statements
+ * it should only be used interactively.
+ */
+void
+sock_dump(isc_socket_t *sock) {
+       isc_socketevent_t *ldev;
+       isc_socket_newconnev_t *ndev;
+
+#if 0
+       isc_sockaddr_t addr;
+       char socktext[256];
+
+       isc_socket_getpeername(sock, &addr);
+       isc_sockaddr_format(&addr, socktext, sizeof(socktext));
+       printf("Remote Socket: %s\n", socktext);
+       isc_socket_getsockname(sock, &addr);
+       isc_sockaddr_format(&addr, socktext, sizeof(socktext));
+       printf("This Socket: %s\n", socktext);
+#endif
+
+       printf("\n\t\tSock Dump\n");
+       printf("\t\tfd: %u\n", sock->fd);
+       printf("\t\treferences: %d\n", sock->references);
+       printf("\t\tpending_accept: %d\n", sock->pending_accept);
+       printf("\t\tconnecting: %d\n", sock->pending_connect);
+       printf("\t\tconnected: %d\n", sock->connected);
+       printf("\t\tbound: %d\n", sock->bound);
+       printf("\t\tpending_iocp: %d\n", sock->pending_iocp);
+       printf("\t\tsocket type: %d\n", sock->type);
+
+       printf("\n\t\tSock Recv List\n");
+       ldev = ISC_LIST_HEAD(sock->recv_list);
+       while (ldev != NULL) {
+               printf("\t\tdev: %p\n", ldev);
+               ldev = ISC_LIST_NEXT(ldev, ev_link);
+       }
+
+       printf("\n\t\tSock Send List\n");
+       ldev = ISC_LIST_HEAD(sock->send_list);
+       while (ldev != NULL) {
+               printf("\t\tdev: %p\n", ldev);
+               ldev = ISC_LIST_NEXT(ldev, ev_link);
+       }
+
+       printf("\n\t\tSock Accept List\n");
+       ndev = ISC_LIST_HEAD(sock->accept_list);
+       while (ndev != NULL) {
+               printf("\t\tdev: %p\n", ldev);
+               ndev = ISC_LIST_NEXT(ndev, ev_link);
+       }
+}
+
+static void
+socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address,
+          isc_logcategory_t *category, isc_logmodule_t *module, int level,
+          isc_msgcat_t *msgcat, int msgset, int message,
+          const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10);
+
+/*  This function will add an entry to the I/O completion port
+ *  that will signal the I/O thread to exit (gracefully)
+ */
+static void
+signal_iocompletionport_exit(isc_socketmgr_t *manager) {
+       int i;
+       int errval;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(VALID_MANAGER(manager));
+       for (i = 0; i < manager->maxIOCPThreads; i++) {
+               if (!PostQueuedCompletionStatus(manager->hIoCompletionPort,
+                                               0, 0, 0)) {
+                       errval = GetLastError();
+                       isc__strerror(errval, strbuf, sizeof(strbuf));
+                       FATAL_ERROR(__FILE__, __LINE__,
+                               isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                               ISC_MSG_FAILED,
+                               "Can't request service thread to exit: %s"),
+                               strbuf);
+               }
+       }
+}
+
+/*
+ * Create the worker threads for the I/O Completion Port
+ */
+void
+iocompletionport_createthreads(int total_threads, isc_socketmgr_t *manager) {
+       int errval;
+       char strbuf[ISC_STRERRORSIZE];
+       int i;
+
+       INSIST(total_threads > 0);
+       REQUIRE(VALID_MANAGER(manager));
+       /*
+        * We need at least one
+        */
+       for (i = 0; i < total_threads; i++) {
+               manager->hIOCPThreads[i] = CreateThread(NULL, 0, SocketIoThread,
+                                               manager, 0,
+                                               &manager->dwIOCPThreadIds[i]);
+               if (manager->hIOCPThreads[i] == NULL) {
+                       errval = GetLastError();
+                       isc__strerror(errval, strbuf, sizeof(strbuf));
+                       FATAL_ERROR(__FILE__, __LINE__,
+                               isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                               ISC_MSG_FAILED,
+                               "Can't create IOCP thread: %s"),
+                               strbuf);
+                       exit(1);
+               }
+       }
+}
+
+/*
+ *  Create/initialise the I/O completion port
+ */
+void
+iocompletionport_init(isc_socketmgr_t *manager) {
+       int errval;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(VALID_MANAGER(manager));
+       /*
+        * Create a private heap to handle the socket overlapped structure
+        * The minimum number of structures is 10, there is no maximum
+        */
+       hHeapHandle = HeapCreate(0, 10 * sizeof(IoCompletionInfo), 0);
+       if (hHeapHandle == NULL) {
+               errval = GetLastError();
+               isc__strerror(errval, strbuf, sizeof(strbuf));
+               FATAL_ERROR(__FILE__, __LINE__,
+                           isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                                          ISC_MSG_FAILED,
+                                          "HeapCreate() failed during "
+                                          "initialization: %s"),
+                           strbuf);
+               exit(1);
+       }
+
+       manager->maxIOCPThreads = min(isc_os_ncpus() + 1, MAX_IOCPTHREADS);
+
+       /* Now Create the Completion Port */
+       manager->hIoCompletionPort = CreateIoCompletionPort(
+                       INVALID_HANDLE_VALUE, NULL,
+                       0, manager->maxIOCPThreads);
+       if (manager->hIoCompletionPort == NULL) {
+               errval = GetLastError();
+               isc__strerror(errval, strbuf, sizeof(strbuf));
+               FATAL_ERROR(__FILE__, __LINE__,
+                               isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                               ISC_MSG_FAILED,
+                               "CreateIoCompletionPort() failed "
+                               "during initialization: %s"),
+                               strbuf);
+               exit(1);
+       }
+
+       /*
+        * Worker threads for servicing the I/O
+        */
+       iocompletionport_createthreads(manager->maxIOCPThreads, manager);
+}
+
+/*
+ * Associate a socket with an IO Completion Port.  This allows us to queue events for it
+ * and have our worker pool of threads process them.
+ */
+void
+iocompletionport_update(isc_socket_t *sock) {
+       HANDLE hiocp;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       hiocp = CreateIoCompletionPort((HANDLE)sock->fd,
+               sock->manager->hIoCompletionPort, (ULONG_PTR)sock, 0);
+
+       if (hiocp == NULL) {
+               DWORD errval = GetLastError();
+               isc__strerror(errval, strbuf, sizeof(strbuf));
+               isc_log_iwrite(isc_lctx,
+                               ISC_LOGCATEGORY_GENERAL,
+                               ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+                               isc_msgcat, ISC_MSGSET_SOCKET,
+                               ISC_MSG_TOOMANYHANDLES,
+                               "iocompletionport_update: failed to open"
+                               " io completion port: %s",
+                               strbuf);
+
+               /* XXXMLG temporary hack to make failures detected.
+                * This function should return errors to the caller, not
+                * exit here.
+                */
+               FATAL_ERROR(__FILE__, __LINE__,
+                               isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                               ISC_MSG_FAILED,
+                               "CreateIoCompletionPort() failed "
+                               "during initialization: %s"),
+                               strbuf);
+               exit(1);
+       }
+
+       InterlockedIncrement(&sock->manager->iocp_total);
+}
+
+/*
+ * Routine to cleanup and then close the socket.
+ * Only close the socket here if it is NOT associated
+ * with an event, otherwise the WSAWaitForMultipleEvents
+ * may fail due to the fact that the Wait should not
+ * be running while closing an event or a socket.
+ * The socket is locked before calling this function
+ */
+void
+socket_close(isc_socket_t *sock) {
+
+       REQUIRE(sock != NULL);
+
+       if (sock->fd != INVALID_SOCKET) {
+               closesocket(sock->fd);
+               sock->fd = INVALID_SOCKET;
+               _set_state(sock, SOCK_CLOSED);
+               InterlockedDecrement(&sock->manager->totalSockets);
+       }
+}
+
+static isc_once_t initialise_once = ISC_ONCE_INIT;
+static isc_boolean_t initialised = ISC_FALSE;
+
+static void
+initialise(void) {
+       WORD wVersionRequested;
+       WSADATA wsaData;
+       int err;
+       SOCKET sock;
+       GUID GUIDConnectEx = WSAID_CONNECTEX;
+       GUID GUIDAcceptEx = WSAID_ACCEPTEX;
+       GUID GUIDGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
+       DWORD dwBytes;
+
+       /* Need Winsock 2.2 or better */
+       wVersionRequested = MAKEWORD(2, 2);
+
+       err = WSAStartup(wVersionRequested, &wsaData);
+       if (err != 0) {
+               char strbuf[ISC_STRERRORSIZE];
+               isc__strerror(err, strbuf, sizeof(strbuf));
+               FATAL_ERROR(__FILE__, __LINE__, "WSAStartup() %s: %s",
+                           isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                          ISC_MSG_FAILED, "failed"),
+                           strbuf);
+               exit(1);
+       }
+       /*
+        * The following APIs do not exist as functions in a library, but we must
+        * ask winsock for them.  They are "extensions" -- but why they cannot be
+        * actual functions is beyond me.  So, ask winsock for the pointers to the
+        * functions we need.
+        */
+       sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       INSIST(sock != INVALID_SOCKET);
+       err = WSAIoctl(sock,  SIO_GET_EXTENSION_FUNCTION_POINTER,
+                &GUIDConnectEx, sizeof(GUIDConnectEx),
+                &ISCConnectEx, sizeof(ISCConnectEx),
+                &dwBytes, NULL, NULL);
+       INSIST(err == 0);
+
+       err = WSAIoctl(sock,  SIO_GET_EXTENSION_FUNCTION_POINTER,
+                &GUIDAcceptEx, sizeof(GUIDAcceptEx),
+                &ISCAcceptEx, sizeof(ISCAcceptEx),
+                &dwBytes, NULL, NULL);
+       INSIST(err == 0);
+
+       err = WSAIoctl(sock,  SIO_GET_EXTENSION_FUNCTION_POINTER,
+                &GUIDGetAcceptExSockaddrs, sizeof(GUIDGetAcceptExSockaddrs),
+                &ISCGetAcceptExSockaddrs, sizeof(ISCGetAcceptExSockaddrs),
+                &dwBytes, NULL, NULL);
+       INSIST(err == 0);
+
+       closesocket(sock);
+
+       initialised = ISC_TRUE;
+}
+
+/*
+ * Initialize socket services
+ */
+void
+InitSockets(void) {
+       RUNTIME_CHECK(isc_once_do(&initialise_once,
+                                 initialise) == ISC_R_SUCCESS);
+       if (!initialised)
+               exit(1);
+}
+
+int
+internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
+                struct msghdr *messagehdr, int flags, int *Error)
+{
+       int Result;
+       DWORD BytesSent;
+       DWORD Flags = flags;
+       int total_sent;
+
+       *Error = 0;
+       Result = WSASendTo(sock->fd, messagehdr->msg_iov,
+                          messagehdr->msg_iovlen, &BytesSent,
+                          Flags, (SOCKADDR *)&messagehdr->to_addr,
+                          messagehdr->to_addr_len, (LPWSAOVERLAPPED)lpo,
+                          NULL);
+
+       total_sent = (int)BytesSent;
+
+       /* Check for errors.*/
+       if (Result == SOCKET_ERROR) {
+               *Error = WSAGetLastError();
+
+               switch (*Error) {
+               case WSA_IO_INCOMPLETE:
+               case WSA_WAIT_IO_COMPLETION:
+               case WSA_IO_PENDING:
+               case NO_ERROR:          /* Strange, but okay */
+                       sock->pending_iocp++;
+                       sock->pending_send++;
+                       break;
+
+               default:
+                       return (-1);
+                       break;
+               }
+       } else {
+               sock->pending_iocp++;
+               sock->pending_send++;
+       }
+
+       if (lpo != NULL)
+               return (0);
+       else
+               return (total_sent);
+}
+
+static void
+queue_receive_request(isc_socket_t *sock) {
+       DWORD Flags = 0;
+       DWORD NumBytes = 0;
+       int total_bytes = 0;
+       int Result;
+       int Error;
+       WSABUF iov[1];
+       IoCompletionInfo *lpo;
+       isc_result_t isc_result;
+
+       /*
+        * If we already have a receive pending, do nothing.
+        */
+       if (sock->pending_recv > 0)
+               return;
+
+       /*
+        * If no one is waiting, do nothing.
+        */
+       if (ISC_LIST_EMPTY(sock->recv_list))
+               return;
+
+       INSIST(sock->recvbuf.remaining == 0);
+       INSIST(sock->fd != INVALID_SOCKET);
+
+       iov[0].len = sock->recvbuf.len;
+       iov[0].buf = sock->recvbuf.base;
+
+       lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+                                           HEAP_ZERO_MEMORY,
+                                           sizeof(IoCompletionInfo));
+       RUNTIME_CHECK(lpo != NULL);
+       lpo->request_type = SOCKET_RECV;
+
+       sock->recvbuf.from_addr_len = sizeof(sock->recvbuf.from_addr);
+
+       Error = 0;
+       Result = WSARecvFrom((SOCKET)sock->fd, iov, 1,
+                            &NumBytes, &Flags,
+                            (SOCKADDR *)&sock->recvbuf.from_addr,
+                            &sock->recvbuf.from_addr_len,
+                            (LPWSAOVERLAPPED)lpo, NULL);
+
+       /* Check for errors. */
+       if (Result == SOCKET_ERROR) {
+               Error = WSAGetLastError();
+
+               switch (Error) {
+               case WSA_IO_PENDING:
+                       sock->pending_iocp++;
+                       sock->pending_recv++;
+                       break;
+
+               default:
+                       isc_result = isc__errno2result(Error);
+                       if (isc_result == ISC_R_UNEXPECTED)
+                               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                       "WSARecvFrom: Windows error code: %d, isc result %d",
+                                       Error, isc_result);
+                       send_recvdone_abort(sock, isc_result);
+                       break;
+               }
+       } else {
+               /*
+                * The recv() finished immediately, but we will still get
+                * a completion event.  Rather than duplicate code, let
+                * that thread handle sending the data along its way.
+                */
+               sock->pending_iocp++;
+               sock->pending_recv++;
+       }
+
+       socket_log(__LINE__, sock, NULL, IOEVENT,
+                  isc_msgcat, ISC_MSGSET_SOCKET,
+                  ISC_MSG_DOIORECV,
+                  "queue_io_request: fd %d result %d error %d",
+                  sock->fd, Result, Error);
+
+       CONSISTENT(sock);
+}
+
+static void
+manager_log(isc_socketmgr_t *sockmgr, isc_logcategory_t *category,
+           isc_logmodule_t *module, int level, const char *fmt, ...)
+{
+       char msgbuf[2048];
+       va_list ap;
+
+       if (!isc_log_wouldlog(isc_lctx, level))
+               return;
+
+       va_start(ap, fmt);
+       vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+       va_end(ap);
+
+       isc_log_write(isc_lctx, category, module, level,
+                     "sockmgr %p: %s", sockmgr, msgbuf);
+}
+
+static void
+socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address,
+          isc_logcategory_t *category, isc_logmodule_t *module, int level,
+          isc_msgcat_t *msgcat, int msgset, int message,
+          const char *fmt, ...)
+{
+       char msgbuf[2048];
+       char peerbuf[256];
+       va_list ap;
+
+
+       if (!isc_log_wouldlog(isc_lctx, level))
+               return;
+
+       va_start(ap, fmt);
+       vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+       va_end(ap);
+
+       if (address == NULL) {
+               isc_log_iwrite(isc_lctx, category, module, level,
+                              msgcat, msgset, message,
+                              "socket %p line %d: %s", sock, lineno, msgbuf);
+       } else {
+               isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
+               isc_log_iwrite(isc_lctx, category, module, level,
+                              msgcat, msgset, message,
+                                  "socket %p line %d peer %s: %s", sock, lineno,
+                                  peerbuf, msgbuf);
+       }
+
+}
+
+/*
+ * Make an fd SOCKET non-blocking.
+ */
+static isc_result_t
+make_nonblock(SOCKET fd) {
+       int ret;
+       unsigned long flags = 1;
+       char strbuf[ISC_STRERRORSIZE];
+
+       /* Set the socket to non-blocking */
+       ret = ioctlsocket(fd, FIONBIO, &flags);
+
+       if (ret == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "ioctlsocket(%d, FIOBIO, %d): %s",
+                                fd, flags, strbuf);
+
+               return (ISC_R_UNEXPECTED);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * Windows 2000 systems incorrectly cause UDP sockets using WASRecvFrom
+ * to not work correctly, returning a WSACONNRESET error when a WSASendTo
+ * fails with an "ICMP port unreachable" response and preventing the
+ * socket from using the WSARecvFrom in subsequent operations.
+ * The function below fixes this, but requires that Windows 2000
+ * Service Pack 2 or later be installed on the system.  NT 4.0
+ * systems are not affected by this and work correctly.
+ * See Microsoft Knowledge Base Article Q263823 for details of this.
+ */
+isc_result_t
+connection_reset_fix(SOCKET fd) {
+       DWORD dwBytesReturned = 0;
+       BOOL  bNewBehavior = FALSE;
+       DWORD status;
+
+       if (isc_win32os_majorversion() < 5)
+               return (ISC_R_SUCCESS); /*  NT 4.0 has no problem */
+
+       /* disable bad behavior using IOCTL: SIO_UDP_CONNRESET */
+       status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior,
+                         sizeof(bNewBehavior), NULL, 0,
+                         &dwBytesReturned, NULL, NULL);
+       if (status != SOCKET_ERROR)
+               return (ISC_R_SUCCESS);
+       else {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "WSAIoctl(SIO_UDP_CONNRESET, oldBehaviour) %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               return (ISC_R_UNEXPECTED);
+       }
+}
+
+/*
+ * Construct an iov array and attach it to the msghdr passed in.  This is
+ * the SEND constructor, which will use the used region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
+ *
+ * Nothing can be NULL, and the done event must list at least one buffer
+ * on the buffer linked list for this function to be meaningful.
+ */
+static void
+build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
+                 struct msghdr *msg, char *cmsg, WSABUF *iov,
+                 IoCompletionInfo  *lpo)
+{
+       unsigned int iovcount;
+       isc_buffer_t *buffer;
+       buflist_t  *cpbuffer;
+       isc_region_t used;
+       size_t write_count;
+       size_t skip_count;
+
+       memset(msg, 0, sizeof(*msg));
+
+       memcpy(&msg->to_addr, &dev->address.type, dev->address.length);
+       msg->to_addr_len = dev->address.length;
+
+       buffer = ISC_LIST_HEAD(dev->bufferlist);
+       write_count = 0;
+       iovcount = 0;
+
+       /*
+        * Single buffer I/O?  Skip what we've done so far in this region.
+        */
+       if (buffer == NULL) {
+               write_count = dev->region.length - dev->n;
+               cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t));
+               RUNTIME_CHECK(cpbuffer != NULL);
+               cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, write_count);
+               RUNTIME_CHECK(cpbuffer->buf != NULL);
+
+               socket_log(__LINE__, sock, NULL, TRACE,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+                  "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t),
+                  cpbuffer->buf, write_count);
+
+               memcpy(cpbuffer->buf,(dev->region.base + dev->n), write_count);
+               cpbuffer->buflen = write_count;
+               ISC_LIST_ENQUEUE(lpo->bufferlist, cpbuffer, link);
+               iov[0].buf = cpbuffer->buf;
+               iov[0].len = write_count;
+               iovcount = 1;
+
+               goto config;
+       }
+
+       /*
+        * Multibuffer I/O.
+        * Skip the data in the buffer list that we have already written.
+        */
+       skip_count = dev->n;
+       while (buffer != NULL) {
+               REQUIRE(ISC_BUFFER_VALID(buffer));
+               if (skip_count < isc_buffer_usedlength(buffer))
+                       break;
+               skip_count -= isc_buffer_usedlength(buffer);
+               buffer = ISC_LIST_NEXT(buffer, link);
+       }
+
+       while (buffer != NULL) {
+               INSIST(iovcount < MAXSCATTERGATHER_SEND);
+
+               isc_buffer_usedregion(buffer, &used);
+
+               if (used.length > 0) {
+                       int uselen = used.length - skip_count;
+                       cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t));
+                       RUNTIME_CHECK(cpbuffer != NULL);
+                       cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, uselen);
+                       RUNTIME_CHECK(cpbuffer->buf != NULL);
+
+                       socket_log(__LINE__, sock, NULL, TRACE,
+                          isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+                          "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t),
+                          cpbuffer->buf, write_count);
+
+                       memcpy(cpbuffer->buf,(used.base + skip_count), uselen);
+                       cpbuffer->buflen = uselen;
+                       iov[iovcount].buf = cpbuffer->buf;
+                       iov[iovcount].len = used.length - skip_count;
+                       write_count += uselen;
+                       skip_count = 0;
+                       iovcount++;
+               }
+               buffer = ISC_LIST_NEXT(buffer, link);
+       }
+
+       INSIST(skip_count == 0);
+
+ config:
+       msg->msg_iov = iov;
+       msg->msg_iovlen = iovcount;
+       msg->msg_totallen = write_count;
+}
+
+static void
+set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
+               isc_socketevent_t *dev)
+{
+       if (sock->type == isc_sockettype_udp) {
+               if (address != NULL)
+                       dev->address = *address;
+               else
+                       dev->address = sock->address;
+       } else if (sock->type == isc_sockettype_tcp) {
+               INSIST(address == NULL);
+               dev->address = sock->address;
+       }
+}
+
+static void
+destroy_socketevent(isc_event_t *event) {
+       isc_socketevent_t *ev = (isc_socketevent_t *)event;
+
+       INSIST(ISC_LIST_EMPTY(ev->bufferlist));
+
+       (ev->destroy)(event);
+}
+
+static isc_socketevent_t *
+allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype,
+                    isc_taskaction_t action, const void *arg)
+{
+       isc_socketevent_t *ev;
+
+       ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx,
+                                                    sock, eventtype,
+                                                    action, arg,
+                                                    sizeof(*ev));
+       if (ev == NULL)
+               return (NULL);
+
+       ev->result = ISC_R_IOERROR; // XXXMLG temporary change to detect failure to set
+       ISC_LINK_INIT(ev, ev_link);
+       ISC_LIST_INIT(ev->bufferlist);
+       ev->region.base = NULL;
+       ev->n = 0;
+       ev->offset = 0;
+       ev->attributes = 0;
+       ev->destroy = ev->ev_destroy;
+       ev->ev_destroy = destroy_socketevent;
+
+       return (ev);
+}
+
+#if defined(ISC_SOCKET_DEBUG)
+static void
+dump_msg(struct msghdr *msg, isc_socket_t *sock) {
+       unsigned int i;
+
+       printf("MSGHDR %p, Socket #: %u\n", msg, sock->fd);
+       printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen);
+       printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen);
+       for (i = 0; i < (unsigned int)msg->msg_iovlen; i++)
+               printf("\t\t%d\tbase %p, len %d\n", i,
+                      msg->msg_iov[i].buf,
+                      msg->msg_iov[i].len);
+}
+#endif
+
+/*
+ * map the error code
+ */
+int
+map_socket_error(isc_socket_t *sock, int windows_errno, int *isc_errno,
+                char *errorstring, size_t bufsize) {
+
+       int doreturn;
+       switch (windows_errno) {
+       case WSAECONNREFUSED:
+               *isc_errno = ISC_R_CONNREFUSED;
+               if (sock->connected)
+                       doreturn = DOIO_HARD;
+               else
+                       doreturn = DOIO_SOFT;
+               break;
+       case WSAENETUNREACH:
+       case ERROR_NETWORK_UNREACHABLE:
+               *isc_errno = ISC_R_NETUNREACH;
+               if (sock->connected)
+                       doreturn = DOIO_HARD;
+               else
+                       doreturn = DOIO_SOFT;
+               break;
+       case ERROR_PORT_UNREACHABLE:
+       case ERROR_HOST_UNREACHABLE:
+       case WSAEHOSTUNREACH:
+               *isc_errno = ISC_R_HOSTUNREACH;
+               if (sock->connected)
+                       doreturn = DOIO_HARD;
+               else
+                       doreturn = DOIO_SOFT;
+               break;
+       case WSAENETDOWN:
+               *isc_errno = ISC_R_NETDOWN;
+               if (sock->connected)
+                       doreturn = DOIO_HARD;
+               else
+                       doreturn = DOIO_SOFT;
+               break;
+       case WSAEHOSTDOWN:
+               *isc_errno = ISC_R_HOSTDOWN;
+               if (sock->connected)
+                       doreturn = DOIO_HARD;
+               else
+                       doreturn = DOIO_SOFT;
+               break;
+       case WSAEACCES:
+               *isc_errno = ISC_R_NOPERM;
+               if (sock->connected)
+                       doreturn = DOIO_HARD;
+               else
+                       doreturn = DOIO_SOFT;
+               break;
+       case WSAECONNRESET:
+       case WSAENETRESET:
+       case WSAECONNABORTED:
+       case WSAEDISCON:
+               *isc_errno = ISC_R_CONNECTIONRESET;
+               if (sock->connected)
+                       doreturn = DOIO_HARD;
+               else
+                       doreturn = DOIO_SOFT;
+               break;
+       case WSAENOTCONN:
+               *isc_errno = ISC_R_NOTCONNECTED;
+               if (sock->connected)
+                       doreturn = DOIO_HARD;
+               else
+                       doreturn = DOIO_SOFT;
+               break;
+       case ERROR_OPERATION_ABORTED:
+       case ERROR_CONNECTION_ABORTED:
+       case ERROR_REQUEST_ABORTED:
+               *isc_errno = ISC_R_CONNECTIONRESET;
+               doreturn = DOIO_HARD;
+               break;
+       case WSAENOBUFS:
+               *isc_errno = ISC_R_NORESOURCES;
+               doreturn = DOIO_HARD;
+               break;
+       case WSAEAFNOSUPPORT:
+               *isc_errno = ISC_R_FAMILYNOSUPPORT;
+               doreturn = DOIO_HARD;
+               break;
+       case WSAEADDRNOTAVAIL:
+               *isc_errno = ISC_R_ADDRNOTAVAIL;
+               doreturn = DOIO_HARD;
+               break;
+       case WSAEDESTADDRREQ:
+               *isc_errno = ISC_R_BADADDRESSFORM;
+               doreturn = DOIO_HARD;
+               break;
+       case ERROR_NETNAME_DELETED:
+               *isc_errno = ISC_R_NETDOWN;
+               doreturn = DOIO_HARD;
+               break;
+       default:
+               *isc_errno = ISC_R_IOERROR;
+               doreturn = DOIO_HARD;
+               break;
+       }
+       if (doreturn == DOIO_HARD) {
+               isc__strerror(windows_errno, errorstring, bufsize);
+       }
+       return (doreturn);
+}
+
+static void
+fill_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
+       isc_region_t r;
+       int copylen;
+       isc_buffer_t *buffer;
+
+       INSIST(dev->n < dev->minimum);
+       INSIST(sock->recvbuf.remaining > 0);
+       INSIST(sock->pending_recv == 0);
+
+       if (sock->type == isc_sockettype_udp) {
+               dev->address.length = sock->recvbuf.from_addr_len;
+               memcpy(&dev->address.type, &sock->recvbuf.from_addr,
+                   sock->recvbuf.from_addr_len);
+               if (isc_sockaddr_getport(&dev->address) == 0) {
+                       if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+                               socket_log(__LINE__, sock, &dev->address, IOEVENT,
+                                          isc_msgcat, ISC_MSGSET_SOCKET,
+                                          ISC_MSG_ZEROPORT,
+                                          "dropping source port zero packet");
+                       }
+                       sock->recvbuf.remaining = 0;
+                       return;
+               }
+       } else if (sock->type == isc_sockettype_tcp) {
+               dev->address = sock->address;
+       }
+
+       /*
+        * Run through the list of buffers we were given, and find the
+        * first one with space.  Once it is found, loop through, filling
+        * the buffers as much as possible.
+        */
+       buffer = ISC_LIST_HEAD(dev->bufferlist);
+       if (buffer != NULL) { // Multi-buffer receive
+               while (buffer != NULL && sock->recvbuf.remaining > 0) {
+                       REQUIRE(ISC_BUFFER_VALID(buffer));
+                       if (isc_buffer_availablelength(buffer) > 0) {
+                               isc_buffer_availableregion(buffer, &r);
+                               copylen = min(r.length, sock->recvbuf.remaining);
+                               memcpy(r.base, sock->recvbuf.consume_position, copylen);
+                               sock->recvbuf.consume_position += copylen;
+                               sock->recvbuf.remaining -= copylen;
+                               isc_buffer_add(buffer, copylen);
+                               dev->n += copylen;
+                       }
+                       buffer = ISC_LIST_NEXT(buffer, link);
+               }
+       } else { // Single-buffer receive
+               copylen = min(dev->region.length - dev->n, sock->recvbuf.remaining);
+               memcpy(dev->region.base + dev->n, sock->recvbuf.consume_position, copylen);
+               sock->recvbuf.consume_position += copylen;
+               sock->recvbuf.remaining -= copylen;
+               dev->n += copylen;
+       }
+
+       /*
+        * UDP receives are all-consuming.  That is, if we have 4k worth of
+        * data in our receive buffer, and the caller only gave us
+        * 1k of space, we will toss the remaining 3k of data.  TCP
+        * will keep the extra data around and use it for later requests.
+        */
+       if (sock->type == isc_sockettype_udp)
+               sock->recvbuf.remaining = 0;
+}
+
+/*
+ * Copy out as much data from the internal buffer to done events.
+ * As each done event is filled, send it along its way.
+ */
+static void
+completeio_recv(isc_socket_t *sock)
+{
+       isc_socketevent_t *dev;
+
+       /*
+        * If we are in the process of filling our buffer, we cannot
+        * touch it yet, so don't.
+        */
+       if (sock->pending_recv > 0)
+               return;
+
+       while (sock->recvbuf.remaining > 0 && !ISC_LIST_EMPTY(sock->recv_list)) {
+               dev = ISC_LIST_HEAD(sock->recv_list);
+
+               /*
+                * See if we have sufficient data in our receive buffer
+                * to handle this.  If we do, copy out the data.
+                */
+               fill_recv(sock, dev);
+
+               /*
+                * Did we satisfy it?
+                */
+               if (dev->n >= dev->minimum) {
+                       dev->result = ISC_R_SUCCESS;
+                       send_recvdone_event(sock, &dev);
+               }
+       }
+}
+
+/*
+ * Returns:
+ *     DOIO_SUCCESS    The operation succeeded.  dev->result contains
+ *                     ISC_R_SUCCESS.
+ *
+ *     DOIO_HARD       A hard or unexpected I/O error was encountered.
+ *                     dev->result contains the appropriate error.
+ *
+ *     DOIO_SOFT       A soft I/O error was encountered.  No senddone
+ *                     event was sent.  The operation should be retried.
+ *
+ *     No other return values are possible.
+ */
+static int
+completeio_send(isc_socket_t *sock, isc_socketevent_t *dev,
+               struct msghdr *messagehdr, int cc, int send_errno)
+{
+       char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+       char strbuf[ISC_STRERRORSIZE];
+
+       if (send_errno != 0) {
+               if (SOFT_ERROR(send_errno))
+                       return (DOIO_SOFT);
+
+               return (map_socket_error(sock, send_errno, &dev->result,
+                       strbuf, sizeof(strbuf)));
+
+               /*
+                * The other error types depend on whether or not the
+                * socket is UDP or TCP.  If it is UDP, some errors
+                * that we expect to be fatal under TCP are merely
+                * annoying, and are really soft errors.
+                *
+                * However, these soft errors are still returned as
+                * a status.
+                */
+               isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf));
+               isc__strerror(send_errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__, "completeio_send: %s: %s",
+                                addrbuf, strbuf);
+               dev->result = isc__errno2result(send_errno);
+       return (DOIO_HARD);
+       }
+
+       /*
+        * If we write less than we expected, update counters, poke.
+        */
+       dev->n += cc;
+       if (cc != messagehdr->msg_totallen)
+               return (DOIO_SOFT);
+
+       /*
+        * Exactly what we wanted to write.  We're done with this
+        * entry.  Post its completion event.
+        */
+       dev->result = ISC_R_SUCCESS;
+       return (DOIO_SUCCESS);
+}
+
+static int
+startio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
+            int *send_errno)
+{
+       char *cmsg = NULL;
+       char strbuf[ISC_STRERRORSIZE];
+       IoCompletionInfo *lpo;
+       int status;
+       struct msghdr *msghdr;
+
+       lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+                                           HEAP_ZERO_MEMORY,
+                                           sizeof(IoCompletionInfo));
+       RUNTIME_CHECK(lpo != NULL);
+       lpo->request_type = SOCKET_SEND;
+       lpo->dev = dev;
+       msghdr = &lpo->messagehdr;
+       memset(msghdr, 0, sizeof(struct msghdr));
+       ISC_LIST_INIT(lpo->bufferlist);
+
+       build_msghdr_send(sock, dev, msghdr, cmsg, sock->iov, lpo);
+
+       *nbytes = internal_sendmsg(sock, lpo, msghdr, 0, send_errno);
+
+       if (*nbytes < 0) {
+               /*
+                * I/O has been initiated
+                * completion will be through the completion port
+                */
+               if (PENDING_ERROR(*send_errno)) {
+                       status = DOIO_PENDING;
+                       goto done;
+               }
+
+               if (SOFT_ERROR(*send_errno)) {
+                       status = DOIO_SOFT;
+                       goto done;
+               }
+
+               /*
+                * If we got this far then something is wrong
+                */
+               if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+                       isc__strerror(*send_errno, strbuf, sizeof(strbuf));
+                       socket_log(__LINE__, sock, NULL, IOEVENT,
+                                  isc_msgcat, ISC_MSGSET_SOCKET,
+                                  ISC_MSG_INTERNALSEND,
+                                  "startio_send: internal_sendmsg(%d) %d "
+                                  "bytes, err %d/%s",
+                                  sock->fd, *nbytes, *send_errno, strbuf);
+               }
+               goto done;
+       }
+       dev->result = ISC_R_SUCCESS;
+       status = DOIO_SOFT;
+ done:
+       _set_state(sock, SOCK_DATA);
+       return (status);
+}
+
+static isc_result_t
+allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
+               isc_socket_t **socketp) {
+       isc_socket_t *sock;
+       isc_result_t result;
+
+       sock = isc_mem_get(manager->mctx, sizeof(*sock));
+
+       if (sock == NULL)
+               return (ISC_R_NOMEMORY);
+
+       sock->magic = 0;
+       sock->references = 0;
+
+       sock->manager = manager;
+       sock->type = type;
+       sock->fd = INVALID_SOCKET;
+
+       ISC_LINK_INIT(sock, link);
+
+       /*
+        * set up list of readers and writers to be initially empty
+        */
+       ISC_LIST_INIT(sock->recv_list);
+       ISC_LIST_INIT(sock->send_list);
+       ISC_LIST_INIT(sock->accept_list);
+       sock->connect_ev = NULL;
+       sock->pending_accept = 0;
+       sock->pending_recv = 0;
+       sock->pending_send = 0;
+       sock->pending_iocp = 0;
+       sock->listener = 0;
+       sock->connected = 0;
+       sock->pending_connect = 0;
+       sock->bound = 0;
+       memset(sock->name, 0, sizeof(sock->name));      // zero the name field
+       _set_state(sock, SOCK_INITIALIZED);
+
+       sock->recvbuf.len = 65536;
+       sock->recvbuf.consume_position = sock->recvbuf.base;
+       sock->recvbuf.remaining = 0;
+       sock->recvbuf.base = isc_mem_get(manager->mctx, sock->recvbuf.len); // max buffer size
+       if (sock->recvbuf.base == NULL) {
+               sock->magic = 0;
+               goto error;
+       }
+
+       /*
+        * initialize the lock
+        */
+       result = isc_mutex_init(&sock->lock);
+       if (result != ISC_R_SUCCESS) {
+               sock->magic = 0;
+               isc_mem_put(manager->mctx, sock->recvbuf.base, sock->recvbuf.len);
+               sock->recvbuf.base = NULL;
+               goto error;
+       }
+
+       socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+                  "allocated");
+
+       sock->magic = SOCKET_MAGIC;
+       *socketp = sock;
+
+       return (ISC_R_SUCCESS);
+
+ error:
+       isc_mem_put(manager->mctx, sock, sizeof(*sock));
+
+       return (result);
+}
+
+/*
+ * Verify that the socket state is consistent.
+ */
+static void
+consistent(isc_socket_t *sock) {
+
+       isc_socketevent_t *dev;
+       isc_socket_newconnev_t *nev;
+       unsigned int count;
+       char *crash_reason;
+       isc_boolean_t crash = ISC_FALSE;
+
+       REQUIRE(sock->pending_iocp == sock->pending_recv + sock->pending_send
+               + sock->pending_accept + sock->pending_connect);
+
+       dev = ISC_LIST_HEAD(sock->send_list);
+       count = 0;
+       while (dev != NULL) {
+               count++;
+               dev = ISC_LIST_NEXT(dev, ev_link);
+       }
+       if (count > sock->pending_send) {
+               crash = ISC_TRUE;
+               crash_reason = "send_list > sock->pending_send";
+       }
+
+       nev = ISC_LIST_HEAD(sock->accept_list);
+       count = 0;
+       while (nev != NULL) {
+               count++;
+               nev = ISC_LIST_NEXT(nev, ev_link);
+       }
+       if (count > sock->pending_accept) {
+               crash = ISC_TRUE;
+               crash_reason = "send_list > sock->pending_send";
+       }
+
+       if (crash) {
+               socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+                          ISC_MSG_DESTROYING, "SOCKET INCONSISTENT: %s",
+                          crash_reason);
+               sock_dump(sock);
+               INSIST(crash == ISC_FALSE);
+       }
+}
+
+/*
+ * Maybe free the socket.
+ *
+ * This function will verify tht the socket is no longer in use in any way,
+ * either internally or externally.  This is the only place where this
+ * check is to be made; if some bit of code believes that IT is done with
+ * the socket (e.g., some reference counter reaches zero), it should call
+ * this function.
+ *
+ * When calling this function, the socket must be locked, and the manager
+ * must be unlocked.
+ *
+ * When this function returns, *socketp will be NULL.  No tricks to try
+ * to hold on to this pointer are allowed.
+ */
+static void
+maybe_free_socket(isc_socket_t **socketp, int lineno) {
+       isc_socket_t *sock = *socketp;
+       *socketp = NULL;
+
+       INSIST(VALID_SOCKET(sock));
+       CONSISTENT(sock);
+
+       if (sock->pending_iocp > 0
+           || sock->pending_recv > 0
+           || sock->pending_send > 0
+           || sock->pending_accept > 0
+           || sock->references > 0
+           || sock->pending_connect == 1
+           || !ISC_LIST_EMPTY(sock->recv_list)
+           || !ISC_LIST_EMPTY(sock->send_list)
+           || !ISC_LIST_EMPTY(sock->accept_list)
+           || sock->fd != INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return;
+       }
+       UNLOCK(&sock->lock);
+
+       free_socket(&sock, lineno);
+}
+
+void
+free_socket(isc_socket_t **sockp, int lineno) {
+       isc_socketmgr_t *manager;
+       isc_socket_t *sock = *sockp;
+       *sockp = NULL;
+
+       manager = sock->manager;
+
+       /*
+        * Seems we can free the socket after all.
+        */
+       manager = sock->manager;
+       socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+                  ISC_MSG_DESTROYING, "freeing socket line %d fd %d lock %p semaphore %p",
+                  lineno, sock->fd, &sock->lock, sock->lock.LockSemaphore);
+
+       sock->magic = 0;
+       DESTROYLOCK(&sock->lock);
+
+       if (sock->recvbuf.base != NULL)
+               isc_mem_put(manager->mctx, sock->recvbuf.base, sock->recvbuf.len);
+
+       LOCK(&manager->lock);
+       if (ISC_LINK_LINKED(sock, link))
+               ISC_LIST_UNLINK(manager->socklist, sock, link);
+       isc_mem_put(manager->mctx, sock, sizeof(*sock));
+
+       if (ISC_LIST_EMPTY(manager->socklist))
+               SIGNAL(&manager->shutdown_ok);
+       UNLOCK(&manager->lock);
+}
+
+/*
+ * Create a new 'type' socket managed by 'manager'.  Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value.  The new socket is returned
+ * in 'socketp'.
+ */
+isc_result_t
+isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
+                 isc_socket_t **socketp) {
+       isc_socket_t *sock = NULL;
+       isc_result_t result;
+#if defined(USE_CMSG)
+       int on = 1;
+#endif
+#if defined(SO_RCVBUF)
+       ISC_SOCKADDR_LEN_T optlen;
+       int size;
+#endif
+       int socket_errno;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(socketp != NULL && *socketp == NULL);
+       REQUIRE(type != isc_sockettype_fdwatch);
+
+       result = allocate_socket(manager, type, &sock);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       sock->pf = pf;
+       switch (type) {
+       case isc_sockettype_udp:
+               sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
+               if (sock->fd != INVALID_SOCKET) {
+                       result = connection_reset_fix(sock->fd);
+                       if (result != ISC_R_SUCCESS) {
+                               socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+                                       "closed %d %d %d con_reset_fix_failed",
+                                       sock->pending_recv, sock->pending_send,
+                                       sock->references);
+                               closesocket(sock->fd);
+                               _set_state(sock, SOCK_CLOSED);
+                               sock->fd = INVALID_SOCKET;
+                               free_socket(&sock, __LINE__);
+                               return (result);
+                       }
+               }
+               break;
+       case isc_sockettype_tcp:
+               sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP);
+               break;
+       }
+
+       if (sock->fd == INVALID_SOCKET) {
+               socket_errno = WSAGetLastError();
+               free_socket(&sock, __LINE__);
+
+               switch (socket_errno) {
+               case WSAEMFILE:
+               case WSAENOBUFS:
+                       return (ISC_R_NORESOURCES);
+
+               case WSAEPROTONOSUPPORT:
+               case WSAEPFNOSUPPORT:
+               case WSAEAFNOSUPPORT:
+                       return (ISC_R_FAMILYNOSUPPORT);
+
+               default:
+                       isc__strerror(socket_errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "socket() %s: %s",
+                                        isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_GENERAL,
+                                                       ISC_MSG_FAILED,
+                                                       "failed"),
+                                        strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+       }
+
+       result = make_nonblock(sock->fd);
+       if (result != ISC_R_SUCCESS) {
+               socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+                       "closed %d %d %d make_nonblock_failed",
+                       sock->pending_recv, sock->pending_send,
+                       sock->references);
+               closesocket(sock->fd);
+               sock->fd = INVALID_SOCKET;
+               free_socket(&sock, __LINE__);
+               return (result);
+       }
+
+
+#if defined(USE_CMSG) || defined(SO_RCVBUF)
+       if (type == isc_sockettype_udp) {
+
+#if defined(USE_CMSG)
+#if defined(ISC_PLATFORM_HAVEIPV6)
+#ifdef IPV6_RECVPKTINFO
+               /* 2292bis */
+               if ((pf == AF_INET6)
+                   && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                                  (void *)&on, sizeof(on)) < 0)) {
+                       isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "setsockopt(%d, IPV6_RECVPKTINFO) "
+                                        "%s: %s", sock->fd,
+                                        isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_GENERAL,
+                                                       ISC_MSG_FAILED,
+                                                       "failed"),
+                                        strbuf);
+               }
+#else
+               /* 2292 */
+               if ((pf == AF_INET6)
+                   && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO,
+                                  (void *)&on, sizeof(on)) < 0)) {
+                       isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "setsockopt(%d, IPV6_PKTINFO) %s: %s",
+                                        sock->fd,
+                                        isc_msgcat_get(isc_msgcat,
+                                                       ISC_MSGSET_GENERAL,
+                                                       ISC_MSG_FAILED,
+                                                       "failed"),
+                                        strbuf);
+               }
+#endif /* IPV6_RECVPKTINFO */
+#ifdef IPV6_USE_MIN_MTU        /*2292bis, not too common yet*/
+               /* use minimum MTU */
+               if (pf == AF_INET6) {
+                       (void)setsockopt(sock->fd, IPPROTO_IPV6,
+                                        IPV6_USE_MIN_MTU,
+                                        (void *)&on, sizeof(on));
+               }
+#endif
+#endif /* ISC_PLATFORM_HAVEIPV6 */
+#endif /* defined(USE_CMSG) */
+
+#if defined(SO_RCVBUF)
+              optlen = sizeof(size);
+              if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+                             (void *)&size, &optlen) >= 0 &&
+                   size < RCVBUFSIZE) {
+                      size = RCVBUFSIZE;
+                      (void)setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+                                       (void *)&size, sizeof(size));
+              }
+#endif
+
+       }
+#endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */
+
+       _set_state(sock, SOCK_OPEN);
+       sock->references = 1;
+       *socketp = sock;
+
+       iocompletionport_update(sock);
+
+       /*
+        * Note we don't have to lock the socket like we normally would because
+        * there are no external references to it yet.
+        */
+       LOCK(&manager->lock);
+       ISC_LIST_APPEND(manager->socklist, sock, link);
+       InterlockedIncrement(&manager->totalSockets);
+       UNLOCK(&manager->lock);
+
+       socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
+                  ISC_MSG_CREATED, "created %u type %u", sock->fd, type);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_open(isc_socket_t *sock) {
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(sock->type != isc_sockettype_fdwatch);
+
+       return (ISC_R_NOTIMPLEMENTED);
+}
+
+/*
+ * Attach to a socket.  Caller must explicitly detach when it is done.
+ */
+void
+isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(socketp != NULL && *socketp == NULL);
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+       sock->references++;
+       UNLOCK(&sock->lock);
+
+       *socketp = sock;
+}
+
+/*
+ * Dereference a socket.  If this is the last reference to it, clean things
+ * up by destroying the socket.
+ */
+void
+isc_socket_detach(isc_socket_t **socketp) {
+       isc_socket_t *sock;
+       isc_boolean_t kill_socket = ISC_FALSE;
+
+       REQUIRE(socketp != NULL);
+       sock = *socketp;
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(sock->type != isc_sockettype_fdwatch);
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+       REQUIRE(sock->references > 0);
+       sock->references--;
+
+       socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+               "detach_socket %d %d %d",
+               sock->pending_recv, sock->pending_send,
+               sock->references);
+
+       if (sock->references == 0 && sock->fd != INVALID_SOCKET) {
+               closesocket(sock->fd);
+               sock->fd = INVALID_SOCKET;
+               _set_state(sock, SOCK_CLOSED);
+       }
+
+       maybe_free_socket(&sock, __LINE__);
+
+       *socketp = NULL;
+}
+
+isc_result_t
+isc_socket_close(isc_socket_t *sock) {
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(sock->type != isc_sockettype_fdwatch);
+
+       return (ISC_R_NOTIMPLEMENTED);
+}
+
+/*
+ * Dequeue an item off the given socket's read queue, set the result code
+ * in the done event to the one provided, and send it to the task it was
+ * destined for.
+ *
+ * If the event to be sent is on a list, remove it before sending.  If
+ * asked to, send and detach from the task as well.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+       isc_task_t *task;
+
+       task = (*dev)->ev_sender;
+       (*dev)->ev_sender = sock;
+
+       if (ISC_LINK_LINKED(*dev, ev_link))
+               ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
+
+       if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+           == ISC_SOCKEVENTATTR_ATTACHED)
+               isc_task_sendanddetach(&task, (isc_event_t **)dev);
+       else
+               isc_task_send(task, (isc_event_t **)dev);
+
+       CONSISTENT(sock);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ */
+static void
+send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+       isc_task_t *task;
+
+       INSIST(dev != NULL && *dev != NULL);
+
+       task = (*dev)->ev_sender;
+       (*dev)->ev_sender = sock;
+
+       if (ISC_LINK_LINKED(*dev, ev_link))
+               ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
+
+       if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
+           == ISC_SOCKEVENTATTR_ATTACHED)
+               isc_task_sendanddetach(&task, (isc_event_t **)dev);
+       else
+               isc_task_send(task, (isc_event_t **)dev);
+
+       CONSISTENT(sock);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ */
+static void
+send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev) {
+       isc_task_t *task;
+
+       INSIST(adev != NULL && *adev != NULL);
+
+       task = (*adev)->ev_sender;
+       (*adev)->ev_sender = sock;
+
+       if (ISC_LINK_LINKED(*adev, ev_link))
+               ISC_LIST_DEQUEUE(sock->accept_list, *adev, ev_link);
+
+       isc_task_sendanddetach(&task, (isc_event_t **)adev);
+
+       CONSISTENT(sock);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ */
+static void
+send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev) {
+       isc_task_t *task;
+
+       INSIST(cdev != NULL && *cdev != NULL);
+
+       task = (*cdev)->ev_sender;
+       (*cdev)->ev_sender = sock;
+
+       sock->connect_ev = NULL;
+
+       isc_task_sendanddetach(&task, (isc_event_t **)cdev);
+
+       CONSISTENT(sock);
+}
+
+/*
+ * On entry to this function, the event delivered is the internal
+ * readable event, and the first item on the accept_list should be
+ * the done event we want to send.  If the list is empty, this is a no-op,
+ * so just close the new connection, unlock, and return.
+ *
+ * Note the socket is locked before entering here
+ */
+static void
+internal_accept(isc_socket_t *sock, IoCompletionInfo *lpo, int accept_errno) {
+       isc_socket_newconnev_t *adev;
+       isc_result_t result = ISC_R_SUCCESS;
+       isc_socket_t *nsock;
+       struct sockaddr *localaddr;
+       int localaddr_len = sizeof(*localaddr);
+       struct sockaddr *remoteaddr;
+       int remoteaddr_len = sizeof(*remoteaddr);
+
+       INSIST(VALID_SOCKET(sock));
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       socket_log(__LINE__, sock, NULL, TRACE,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+                  "internal_accept called");
+
+       INSIST(sock->listener);
+
+       INSIST(sock->pending_iocp > 0);
+       sock->pending_iocp--;
+       INSIST(sock->pending_accept > 0);
+       sock->pending_accept--;
+
+       adev = lpo->adev;
+
+       /*
+        * If the event is no longer in the list we can just return.
+        */
+       if (!acceptdone_is_active(sock, adev))
+               goto done;
+
+       nsock = adev->newsocket;
+
+       /*
+        * Pull off the done event.
+        */
+       ISC_LIST_UNLINK(sock->accept_list, adev, ev_link);
+
+       /*
+        * Extract the addresses from the socket, copy them into the structure,
+        * and return the new socket.
+        */
+       ISCGetAcceptExSockaddrs(lpo->acceptbuffer, 0,
+               sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16,
+               (LPSOCKADDR *)&localaddr, &localaddr_len,
+               (LPSOCKADDR *)&remoteaddr, &remoteaddr_len);
+       memcpy(&adev->address.type, remoteaddr, remoteaddr_len);
+       adev->address.length = remoteaddr_len;
+       nsock->address = adev->address;
+       nsock->pf = adev->address.type.sa.sa_family;
+
+       socket_log(__LINE__, nsock, &nsock->address, TRACE,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+                  "internal_accept parent %p", sock);
+
+       result = make_nonblock(adev->newsocket->fd);
+       INSIST(result == ISC_R_SUCCESS);
+
+       INSIST(setsockopt(nsock->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+              (char *)&sock->fd, sizeof(sock->fd)) == 0);
+
+       /*
+        * Hook it up into the manager.
+        */
+       nsock->bound = 1;
+       nsock->connected = 1;
+       _set_state(nsock, SOCK_OPEN);
+
+       LOCK(&nsock->manager->lock);
+       ISC_LIST_APPEND(nsock->manager->socklist, nsock, link);
+       InterlockedIncrement(&nsock->manager->totalSockets);
+       UNLOCK(&nsock->manager->lock);
+
+       socket_log(__LINE__, sock, &nsock->address, CREATION,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
+                  "accepted_connection new_socket %p fd %d",
+                  nsock, nsock->fd);
+
+       adev->result = result;
+       send_acceptdone_event(sock, &adev);
+
+done:
+       CONSISTENT(sock);
+       UNLOCK(&sock->lock);
+
+       HeapFree(hHeapHandle, 0, lpo->acceptbuffer);
+       lpo->acceptbuffer = NULL;
+}
+
+/*
+ * Called when a socket with a pending connect() finishes.
+ * Note that the socket is locked before entering.
+ */
+static void
+internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) {
+       isc_socket_connev_t *cdev;
+       char strbuf[ISC_STRERRORSIZE];
+
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+
+       INSIST(sock->pending_iocp > 0);
+       sock->pending_iocp--;
+       INSIST(sock->pending_connect == 1);
+       sock->pending_connect = 0;
+
+       /*
+        * Has this event been canceled?
+        */
+       cdev = lpo->cdev;
+       if (!connectdone_is_active(sock, cdev)) {
+               sock->pending_connect = 0;
+               if (sock->fd != INVALID_SOCKET) {
+                       closesocket(sock->fd);
+                       sock->fd = INVALID_SOCKET;
+                       _set_state(sock, SOCK_CLOSED);
+               }
+               CONSISTENT(sock);
+               UNLOCK(&sock->lock);
+               return;
+       }
+
+       /*
+        * Check possible Windows network event error status here.
+        */
+       if (connect_errno != 0) {
+               /*
+                * If the error is SOFT, just try again on this
+                * fd and pretend nothing strange happened.
+                */
+               if (SOFT_ERROR(connect_errno) ||
+                   connect_errno == WSAEINPROGRESS) {
+                       sock->pending_connect = 1;
+                       CONSISTENT(sock);
+                       UNLOCK(&sock->lock);
+                       return;
+               }
+
+               /*
+                * Translate other errors into ISC_R_* flavors.
+                */
+               switch (connect_errno) {
+#define ERROR_MATCH(a, b) case a: cdev->result = b; break;
+                       ERROR_MATCH(WSAEACCES, ISC_R_NOPERM);
+                       ERROR_MATCH(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+                       ERROR_MATCH(WSAEAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+                       ERROR_MATCH(WSAECONNREFUSED, ISC_R_CONNREFUSED);
+                       ERROR_MATCH(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH);
+                       ERROR_MATCH(WSAEHOSTDOWN, ISC_R_HOSTDOWN);
+                       ERROR_MATCH(WSAENETUNREACH, ISC_R_NETUNREACH);
+                       ERROR_MATCH(WSAENETDOWN, ISC_R_NETDOWN);
+                       ERROR_MATCH(WSAENOBUFS, ISC_R_NORESOURCES);
+                       ERROR_MATCH(WSAECONNRESET, ISC_R_CONNECTIONRESET);
+                       ERROR_MATCH(WSAECONNABORTED, ISC_R_CONNECTIONRESET);
+                       ERROR_MATCH(WSAETIMEDOUT, ISC_R_TIMEDOUT);
+#undef ERROR_MATCH
+               default:
+                       cdev->result = ISC_R_UNEXPECTED;
+                       isc__strerror(connect_errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                        "internal_connect: connect() %s",
+                                        strbuf);
+               }
+       } else {
+               INSIST(setsockopt(sock->fd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == 0);
+               cdev->result = ISC_R_SUCCESS;
+               sock->connected = 1;
+               socket_log(__LINE__, sock, &sock->address, IOEVENT,
+                          isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
+                          "internal_connect: success");
+       }
+
+       send_connectdone_event(sock, &cdev);
+
+       UNLOCK(&sock->lock);
+}
+
+/*
+ * Loop through the socket, returning ISC_R_EOF for each done event pending.
+ */
+static void
+send_recvdone_abort(isc_socket_t *sock, isc_result_t result) {
+       isc_socketevent_t *dev;
+
+       while (!ISC_LIST_EMPTY(sock->recv_list)) {
+               dev = ISC_LIST_HEAD(sock->recv_list);
+               dev->result = result;
+               send_recvdone_event(sock, &dev);
+       }
+}
+
+/*
+ * Take the data we received in our private buffer, and if any recv() calls on
+ * our list are satisfied, send the corresponding done event.
+ *
+ * If we need more data (there are still items on the recv_list after we consume all
+ * our data) then arrange for another system recv() call to fill our buffers.
+ */
+static void
+internal_recv(isc_socket_t *sock, int nbytes)
+{
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       socket_log(__LINE__, sock, NULL, IOEVENT,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
+                  "internal_recv: %d bytes received", nbytes);
+
+       /*
+        * If we got here, the I/O operation succeeded.  However, we might still have removed this
+        * event from our notification list (or never placed it on it due to immediate completion.)
+        * Handle the reference counting here, and handle the cancellation event just after.
+        */
+       INSIST(sock->pending_iocp > 0);
+       sock->pending_iocp--;
+       INSIST(sock->pending_recv > 0);
+       sock->pending_recv--;
+
+       /*
+        * The only way we could have gotten here is that our I/O has successfully completed.
+        * Update our pointers, and move on.  The only odd case here is that we might not
+        * have received enough data on a TCP stream to satisfy the minimum requirements.  If
+        * this is the case, we will re-issue the recv() call for what we need.
+        *
+        * We do check for a recv() of 0 bytes on a TCP stream.  This means the remote end
+        * has closed.
+        */
+       if (nbytes == 0 && sock->type == isc_sockettype_tcp) {
+               send_recvdone_abort(sock, ISC_R_EOF);
+               maybe_free_socket(&sock, __LINE__);
+               return;
+       }
+       sock->recvbuf.remaining = nbytes;
+       sock->recvbuf.consume_position = sock->recvbuf.base;
+       completeio_recv(sock);
+
+       /*
+        * If there are more receivers waiting for data, queue another receive
+        * here.
+        */
+       queue_receive_request(sock);
+
+       /*
+        * Unlock and/or destroy if we are the last thing this socket has left to do.
+        */
+       maybe_free_socket(&sock, __LINE__);
+}
+
+static void
+internal_send(isc_socket_t *sock, isc_socketevent_t *dev,
+             struct msghdr *messagehdr, int nbytes, int send_errno, IoCompletionInfo *lpo)
+{
+       buflist_t *buffer;
+
+       /*
+        * Find out what socket this is and lock it.
+        */
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       socket_log(__LINE__, sock, NULL, IOEVENT,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
+                  "internal_send: task got socket event %p", dev);
+
+       buffer = ISC_LIST_HEAD(lpo->bufferlist);
+       while (buffer != NULL) {
+               ISC_LIST_DEQUEUE(lpo->bufferlist, buffer, link);
+
+               socket_log(__LINE__, sock, NULL, TRACE,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
+                  "free_buffer %p %p", buffer, buffer->buf);
+
+               HeapFree(hHeapHandle, 0, buffer->buf);
+               HeapFree(hHeapHandle, 0, buffer);
+               buffer = ISC_LIST_HEAD(lpo->bufferlist);
+       }
+
+       INSIST(sock->pending_iocp > 0);
+       sock->pending_iocp--;
+       INSIST(sock->pending_send > 0);
+       sock->pending_send--;
+
+       /* If the event is no longer in the list we can just return */
+       if (!senddone_is_active(sock, dev))
+               goto done;
+
+       /*
+        * Set the error code and send things on its way.
+        */
+       switch (completeio_send(sock, dev, messagehdr, nbytes, send_errno)) {
+       case DOIO_SOFT:
+               break;
+       case DOIO_HARD:
+       case DOIO_SUCCESS:
+               send_senddone_event(sock, &dev);
+               break;
+       }
+
+ done:
+       maybe_free_socket(&sock, __LINE__);
+}
+
+/*
+ * These return if the done event passed in is on the list (or for connect, is
+ * the one we're waiting for.  Using these ensures we will not double-send an
+ * event.
+ */
+static isc_boolean_t
+senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev)
+{
+       isc_socketevent_t *ldev;
+
+       ldev = ISC_LIST_HEAD(sock->send_list);
+       while (ldev != NULL && ldev != dev)
+               ldev = ISC_LIST_NEXT(ldev, ev_link);
+
+       return (ldev == NULL ? ISC_FALSE : ISC_TRUE);
+}
+
+static isc_boolean_t
+acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev)
+{
+       isc_socket_newconnev_t *ldev;
+
+       ldev = ISC_LIST_HEAD(sock->accept_list);
+       while (ldev != NULL && ldev != dev)
+               ldev = ISC_LIST_NEXT(ldev, ev_link);
+
+       return (ldev == NULL ? ISC_FALSE : ISC_TRUE);
+}
+
+static isc_boolean_t
+connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev)
+{
+       return (sock->connect_ev == dev ? ISC_TRUE : ISC_FALSE);
+}
+
+/*
+ * This is the I/O Completion Port Worker Function. It loops forever
+ * waiting for I/O to complete and then forwards them for further
+ * processing. There are a number of these in separate threads.
+ */
+static isc_threadresult_t WINAPI
+SocketIoThread(LPVOID ThreadContext) {
+       isc_socketmgr_t *manager = ThreadContext;
+       BOOL bSuccess = FALSE;
+       DWORD nbytes;
+       IoCompletionInfo *lpo = NULL;
+       isc_socket_t *sock = NULL;
+       int request;
+       struct msghdr *messagehdr = NULL;
+       int errval;
+       char strbuf[ISC_STRERRORSIZE];
+       int errstatus;
+
+       REQUIRE(VALID_MANAGER(manager));
+
+       /*
+        * Set the thread priority high enough so I/O will
+        * preempt normal recv packet processing, but not
+        * higher than the timer sync thread.
+        */
+       if (!SetThreadPriority(GetCurrentThread(),
+                              THREAD_PRIORITY_ABOVE_NORMAL)) {
+               errval = GetLastError();
+               isc__strerror(errval, strbuf, sizeof(strbuf));
+               FATAL_ERROR(__FILE__, __LINE__,
+                               isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                               ISC_MSG_FAILED,
+                               "Can't set thread priority: %s"),
+                               strbuf);
+       }
+
+       /*
+        * Loop forever waiting on I/O Completions and then processing them
+        */
+       while (TRUE) {
+               bSuccess = GetQueuedCompletionStatus(manager->hIoCompletionPort,
+                                                    &nbytes, (LPDWORD)&sock,
+                                                    (LPWSAOVERLAPPED *)&lpo,
+                                                    INFINITE);
+               if (lpo == NULL) /* Received request to exit */
+                       break;
+
+               REQUIRE(VALID_SOCKET(sock));
+
+               request = lpo->request_type;
+
+               errstatus = 0;
+               if (!bSuccess) {
+                       isc_result_t isc_result;
+
+                       /*
+                        * Did the I/O operation complete?
+                        */
+                       errstatus = WSAGetLastError();
+                       isc_result = isc__errno2resultx(errstatus, __FILE__, __LINE__);
+
+                       LOCK(&sock->lock);
+                       CONSISTENT(sock);
+                       switch (request) {
+                       case SOCKET_RECV:
+                               INSIST(sock->pending_iocp > 0);
+                               sock->pending_iocp--;
+                               INSIST(sock->pending_recv > 0);
+                               sock->pending_recv--;
+                               send_recvdone_abort(sock, isc_result);
+                               if (isc_result == ISC_R_UNEXPECTED) {
+                                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                               "SOCKET_RECV: Windows error code: %d, returning ISC error %d",
+                                               errstatus, isc_result);
+                               }
+                               break;
+
+                       case SOCKET_SEND:
+                               INSIST(sock->pending_iocp > 0);
+                               sock->pending_iocp--;
+                               INSIST(sock->pending_send > 0);
+                               sock->pending_send--;
+                               if (senddone_is_active(sock, lpo->dev)) {
+                                       lpo->dev->result = isc_result;
+                                       socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+                                               "canceled_send");
+                                       send_senddone_event(sock, &lpo->dev);
+                               }
+                               break;
+
+                       case SOCKET_ACCEPT:
+                               INSIST(sock->pending_iocp > 0);
+                               sock->pending_iocp--;
+                               INSIST(sock->pending_accept > 0);
+                               sock->pending_accept--;
+                               if (acceptdone_is_active(sock, lpo->adev)) {
+                                       closesocket(lpo->adev->newsocket->fd);
+                                       lpo->adev->newsocket->fd = INVALID_SOCKET;
+                                       lpo->adev->newsocket->references--;
+                                       free_socket(&lpo->adev->newsocket, __LINE__);
+                                       lpo->adev->result = isc_result;
+                                       socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+                                               "canceled_accept");
+                                       send_acceptdone_event(sock, &lpo->adev);
+                               }
+                               break;
+
+                       case SOCKET_CONNECT:
+                               INSIST(sock->pending_iocp > 0);
+                               sock->pending_iocp--;
+                               INSIST(sock->pending_connect == 1);
+                               sock->pending_connect = 0;
+                               if (connectdone_is_active(sock, lpo->cdev)) {
+                                       lpo->cdev->result = isc_result;
+                                       socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+                                               "canceled_connect");
+                                       send_connectdone_event(sock, &lpo->cdev);
+                               }
+                               break;
+                       }
+                       maybe_free_socket(&sock, __LINE__);
+
+                       if (lpo != NULL)
+                               HeapFree(hHeapHandle, 0, lpo);
+                       continue;
+               }
+
+               messagehdr = &lpo->messagehdr;
+
+               switch (request) {
+               case SOCKET_RECV:
+                       internal_recv(sock, nbytes);
+                       break;
+               case SOCKET_SEND:
+                       internal_send(sock, lpo->dev, messagehdr, nbytes, errstatus, lpo);
+                       break;
+               case SOCKET_ACCEPT:
+                       internal_accept(sock, lpo, errstatus);
+                       break;
+               case SOCKET_CONNECT:
+                       internal_connect(sock, lpo, errstatus);
+                       break;
+               }
+
+               if (lpo != NULL)
+                       HeapFree(hHeapHandle, 0, lpo);
+       }
+
+       /*
+        * Exit Completion Port Thread
+        */
+       manager_log(manager, TRACE,
+                   isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                  ISC_MSG_EXITING, "SocketIoThread exiting"));
+       return ((isc_threadresult_t)0);
+}
+
+/*
+ * Create a new socket manager.
+ */
+isc_result_t
+isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
+       return (isc_socketmgr_create2(mctx, managerp, 0));
+}
+
+isc_result_t
+isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
+                    unsigned int maxsocks)
+{
+       isc_socketmgr_t *manager;
+       isc_result_t result;
+
+       REQUIRE(managerp != NULL && *managerp == NULL);
+
+       if (maxsocks != 0)
+               return (ISC_R_NOTIMPLEMENTED);
+
+       manager = isc_mem_get(mctx, sizeof(*manager));
+       if (manager == NULL)
+               return (ISC_R_NOMEMORY);
+
+       InitSockets();
+
+       manager->magic = SOCKET_MANAGER_MAGIC;
+       manager->mctx = NULL;
+       manager->stats = NULL;
+       ISC_LIST_INIT(manager->socklist);
+       result = isc_mutex_init(&manager->lock);
+       if (result != ISC_R_SUCCESS) {
+               isc_mem_put(mctx, manager, sizeof(*manager));
+               return (result);
+       }
+       if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
+               DESTROYLOCK(&manager->lock);
+               isc_mem_put(mctx, manager, sizeof(*manager));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_condition_init() %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               return (ISC_R_UNEXPECTED);
+       }
+
+       isc_mem_attach(mctx, &manager->mctx);
+
+       iocompletionport_init(manager); /* Create the Completion Ports */
+
+       manager->bShutdown = ISC_FALSE;
+       manager->totalSockets = 0;
+       manager->iocp_total = 0;
+
+       *managerp = manager;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) {
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(nsockp != NULL);
+
+       return (ISC_R_NOTIMPLEMENTED);
+}
+
+void
+isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) {
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(ISC_LIST_EMPTY(manager->socklist));
+       REQUIRE(manager->stats == NULL);
+       REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max);
+
+       isc_stats_attach(stats, &manager->stats);
+}
+
+void
+isc_socketmgr_destroy(isc_socketmgr_t **managerp) {
+       isc_socketmgr_t *manager;
+       int i;
+       isc_mem_t *mctx;
+
+       /*
+        * Destroy a socket manager.
+        */
+
+       REQUIRE(managerp != NULL);
+       manager = *managerp;
+       REQUIRE(VALID_MANAGER(manager));
+
+       LOCK(&manager->lock);
+
+       /*
+        * Wait for all sockets to be destroyed.
+        */
+       while (!ISC_LIST_EMPTY(manager->socklist)) {
+               manager_log(manager, CREATION,
+                           isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+                                          ISC_MSG_SOCKETSREMAIN,
+                                          "sockets exist"));
+               WAIT(&manager->shutdown_ok, &manager->lock);
+       }
+
+       UNLOCK(&manager->lock);
+
+       /*
+        * Here, we need to had some wait code for the completion port
+        * thread.
+        */
+       signal_iocompletionport_exit(manager);
+       manager->bShutdown = ISC_TRUE;
+
+       /*
+        * Wait for threads to exit.
+        */
+       for (i = 0; i < manager->maxIOCPThreads; i++) {
+               if (isc_thread_join((isc_thread_t) manager->hIOCPThreads[i],
+                       NULL) != ISC_R_SUCCESS)
+                       UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_thread_join() for Completion Port %s",
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+       }
+       /*
+        * Clean up.
+        */
+
+       CloseHandle(manager->hIoCompletionPort);
+
+       (void)isc_condition_destroy(&manager->shutdown_ok);
+
+       DESTROYLOCK(&manager->lock);
+       if (manager->stats != NULL)
+               isc_stats_detach(&manager->stats);
+       manager->magic = 0;
+       mctx= manager->mctx;
+       isc_mem_put(mctx, manager, sizeof(*manager));
+
+       isc_mem_detach(&mctx);
+
+       *managerp = NULL;
+}
+
+static void
+queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev)
+{
+       isc_task_t *ntask = NULL;
+
+       isc_task_attach(task, &ntask);
+       dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+       /*
+        * Enqueue the request.
+        */
+       INSIST(!ISC_LINK_LINKED(dev, ev_link));
+       ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
+
+       socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+                  "queue_receive_event: event %p -> task %p",
+                  dev, ntask);
+}
+
+/*
+ * Check the pending receive queue, and if we have data pending, give it to this
+ * caller.  If we have none, queue an I/O request.  If this caller is not the first
+ * on the list, then we will just queue this event and return.
+ *
+ * Caller must have the socket locked.
+ */
+static isc_result_t
+socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+           unsigned int flags)
+{
+       int cc = 0;
+       isc_task_t *ntask = NULL;
+       isc_result_t result = ISC_R_SUCCESS;
+       int recv_errno = 0;
+
+       dev->ev_sender = task;
+
+       if (sock->fd == INVALID_SOCKET)
+               return (ISC_R_EOF);
+
+       /*
+        * Queue our event on the list of things to do.  Call our function to
+        * attempt to fill buffers as much as possible, and return done events.
+        * We are going to lie about our handling of the ISC_SOCKFLAG_IMMEDIATE
+        * here and tell our caller that we could not satisfy it immediately.
+        */
+       queue_receive_event(sock, task, dev);
+       if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+               result = ISC_R_INPROGRESS;
+
+       completeio_recv(sock);
+
+       /*
+        * If there are more receivers waiting for data, queue another receive
+        * here.  If the
+        */
+       queue_receive_request(sock);
+
+       return (result);
+}
+
+isc_result_t
+isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+                unsigned int minimum, isc_task_t *task,
+                isc_taskaction_t action, const void *arg)
+{
+       isc_socketevent_t *dev;
+       isc_socketmgr_t *manager;
+       unsigned int iocount;
+       isc_buffer_t *buffer;
+       isc_result_t ret;
+
+       REQUIRE(VALID_SOCKET(sock));
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * Make sure that the socket is not closed.  XXXMLG change error here?
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+
+       REQUIRE(buflist != NULL);
+       REQUIRE(!ISC_LIST_EMPTY(*buflist));
+       REQUIRE(task != NULL);
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       iocount = isc_bufferlist_availablecount(buflist);
+       REQUIRE(iocount > 0);
+
+       INSIST(sock->bound);
+
+       dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
+       if (dev == NULL) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_NOMEMORY);
+       }
+
+       /*
+        * UDP sockets are always partial read
+        */
+       if (sock->type == isc_sockettype_udp)
+               dev->minimum = 1;
+       else {
+               if (minimum == 0)
+                       dev->minimum = iocount;
+               else
+                       dev->minimum = minimum;
+       }
+
+       /*
+        * Move each buffer from the passed in list to our internal one.
+        */
+       buffer = ISC_LIST_HEAD(*buflist);
+       while (buffer != NULL) {
+               ISC_LIST_DEQUEUE(*buflist, buffer, link);
+               ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+               buffer = ISC_LIST_HEAD(*buflist);
+       }
+
+       ret = socket_recv(sock, dev, task, 0);
+
+       UNLOCK(&sock->lock);
+       return (ret);
+}
+
+isc_result_t
+isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
+               isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       isc_socketevent_t *dev;
+       isc_socketmgr_t *manager;
+       isc_result_t ret;
+
+       REQUIRE(VALID_SOCKET(sock));
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       INSIST(sock->bound);
+
+       dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
+       if (dev == NULL) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_NOMEMORY);
+       }
+
+       ret = isc_socket_recv2(sock, region, minimum, task, dev, 0);
+       UNLOCK(&sock->lock);
+       return (ret);
+}
+
+isc_result_t
+isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
+                unsigned int minimum, isc_task_t *task,
+                isc_socketevent_t *event, unsigned int flags)
+{
+       isc_result_t ret;
+
+       REQUIRE(VALID_SOCKET(sock));
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       event->result = ISC_R_UNEXPECTED;
+       event->ev_sender = sock;
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+
+       ISC_LIST_INIT(event->bufferlist);
+       event->region = *region;
+       event->n = 0;
+       event->offset = 0;
+       event->attributes = 0;
+
+       /*
+        * UDP sockets are always partial read.
+        */
+       if (sock->type == isc_sockettype_udp)
+               event->minimum = 1;
+       else {
+               if (minimum == 0)
+                       event->minimum = region->length;
+               else
+                       event->minimum = minimum;
+       }
+
+       ret = socket_recv(sock, event, task, flags);
+       UNLOCK(&sock->lock);
+       return (ret);
+}
+
+/*
+ * Caller must have the socket locked.
+ */
+static isc_result_t
+socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+           isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+           unsigned int flags)
+{
+       int io_state;
+       int send_errno = 0;
+       int cc = 0;
+       isc_task_t *ntask = NULL;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       dev->ev_sender = task;
+
+       set_dev_address(address, sock, dev);
+       if (pktinfo != NULL) {
+               socket_log(__LINE__, sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET,
+                          ISC_MSG_PKTINFOPROVIDED,
+                          "pktinfo structure provided, ifindex %u (set to 0)",
+                          pktinfo->ipi6_ifindex);
+
+               dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
+               dev->pktinfo = *pktinfo;
+               /*
+                * Set the pktinfo index to 0 here, to let the kernel decide
+                * what interface it should send on.
+                */
+               dev->pktinfo.ipi6_ifindex = 0;
+       }
+
+       io_state = startio_send(sock, dev, &cc, &send_errno);
+       switch (io_state) {
+       case DOIO_PENDING:      /* I/O started. Nothing more to do */
+       case DOIO_SOFT:
+               /*
+                * We couldn't send all or part of the request right now, so
+                * queue it unless ISC_SOCKFLAG_NORETRY is set.
+                */
+               if ((flags & ISC_SOCKFLAG_NORETRY) == 0) {
+                       isc_task_attach(task, &ntask);
+                       dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+                       /*
+                        * Enqueue the request.
+                        */
+                       INSIST(!ISC_LINK_LINKED(dev, ev_link));
+                       ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
+
+                       socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
+                                  "socket_send: event %p -> task %p",
+                                  dev, ntask);
+
+                       if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
+                               result = ISC_R_INPROGRESS;
+                       break;
+               }
+
+       case DOIO_SUCCESS:
+               break;
+       }
+
+       return (result);
+}
+
+isc_result_t
+isc_socket_send(isc_socket_t *sock, isc_region_t *region,
+               isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       /*
+        * REQUIRE() checking is performed in isc_socket_sendto().
+        */
+       return (isc_socket_sendto(sock, region, task, action, arg, NULL,
+                                 NULL));
+}
+
+isc_result_t
+isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
+                 isc_task_t *task, isc_taskaction_t action, const void *arg,
+                 isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+       isc_socketevent_t *dev;
+       isc_socketmgr_t *manager;
+       isc_result_t ret;
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(sock->type != isc_sockettype_fdwatch);
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+       REQUIRE(region != NULL);
+       REQUIRE(task != NULL);
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       INSIST(sock->bound);
+
+       dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
+       if (dev == NULL) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_NOMEMORY);
+       }
+       dev->region = *region;
+
+       ret = socket_send(sock, dev, task, address, pktinfo, 0);
+       UNLOCK(&sock->lock);
+       return (ret);
+}
+
+isc_result_t
+isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
+                isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       return (isc_socket_sendtov(sock, buflist, task, action, arg, NULL,
+                                  NULL));
+}
+
+isc_result_t
+isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
+                  isc_task_t *task, isc_taskaction_t action, const void *arg,
+                  isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
+{
+       isc_socketevent_t *dev;
+       isc_socketmgr_t *manager;
+       unsigned int iocount;
+       isc_buffer_t *buffer;
+       isc_result_t ret;
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+       REQUIRE(buflist != NULL);
+       REQUIRE(!ISC_LIST_EMPTY(*buflist));
+       REQUIRE(task != NULL);
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       iocount = isc_bufferlist_usedcount(buflist);
+       REQUIRE(iocount > 0);
+
+       dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
+       if (dev == NULL) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_NOMEMORY);
+       }
+
+       /*
+        * Move each buffer from the passed in list to our internal one.
+        */
+       buffer = ISC_LIST_HEAD(*buflist);
+       while (buffer != NULL) {
+               ISC_LIST_DEQUEUE(*buflist, buffer, link);
+               ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
+               buffer = ISC_LIST_HEAD(*buflist);
+       }
+
+       ret = socket_send(sock, dev, task, address, pktinfo, 0);
+       UNLOCK(&sock->lock);
+       return (ret);
+}
+
+isc_result_t
+isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+                  isc_task_t *task,
+                  isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+                  isc_socketevent_t *event, unsigned int flags)
+{
+       isc_result_t ret;
+
+       REQUIRE(VALID_SOCKET(sock));
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0);
+       if ((flags & ISC_SOCKFLAG_NORETRY) != 0)
+               REQUIRE(sock->type == isc_sockettype_udp);
+       event->ev_sender = sock;
+       event->result = ISC_R_UNEXPECTED;
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+       ISC_LIST_INIT(event->bufferlist);
+       event->region = *region;
+       event->n = 0;
+       event->offset = 0;
+       event->attributes = 0;
+
+       ret = socket_send(sock, event, task, address, pktinfo, flags);
+       UNLOCK(&sock->lock);
+       return (ret);
+}
+
+isc_result_t
+isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr,
+               unsigned int options) {
+       int bind_errno;
+       char strbuf[ISC_STRERRORSIZE];
+       int on = 1;
+
+       REQUIRE(VALID_SOCKET(sock));
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+
+       INSIST(!sock->bound);
+
+       if (sock->pf != sockaddr->type.sa.sa_family) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_FAMILYMISMATCH);
+       }
+       /*
+        * Only set SO_REUSEADDR when we want a specific port.
+        */
+       if ((options & ISC_SOCKET_REUSEADDRESS) != 0 &&
+           isc_sockaddr_getport(sockaddr) != (in_port_t)0 &&
+           setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
+                      sizeof(on)) < 0) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "setsockopt(%d) %s", sock->fd,
+                                isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED, "failed"));
+               /* Press on... */
+       }
+       if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) {
+               bind_errno = WSAGetLastError();
+               UNLOCK(&sock->lock);
+               switch (bind_errno) {
+               case WSAEACCES:
+                       return (ISC_R_NOPERM);
+               case WSAEADDRNOTAVAIL:
+                       return (ISC_R_ADDRNOTAVAIL);
+               case WSAEADDRINUSE:
+                       return (ISC_R_ADDRINUSE);
+               case WSAEINVAL:
+                       return (ISC_R_BOUND);
+               default:
+                       isc__strerror(bind_errno, strbuf, sizeof(strbuf));
+                       UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
+                                        strbuf);
+                       return (ISC_R_UNEXPECTED);
+               }
+       }
+
+       socket_log(__LINE__, sock, sockaddr, TRACE,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound");
+       sock->bound = 1;
+
+       UNLOCK(&sock->lock);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_filter(isc_socket_t *sock, const char *filter) {
+       UNUSED(sock);
+       UNUSED(filter);
+
+       REQUIRE(VALID_SOCKET(sock));
+       return (ISC_R_NOTIMPLEMENTED);
+}
+
+/*
+ * Set up to listen on a given socket.  We do this by creating an internal
+ * event that will be dispatched when the socket has read activity.  The
+ * watcher will send the internal event to the task when there is a new
+ * connection.
+ *
+ * Unlike in read, we don't preallocate a done event here.  Every time there
+ * is a new connection we'll have to allocate a new one anyway, so we might
+ * as well keep things simple rather than having to track them.
+ */
+isc_result_t
+isc_socket_listen(isc_socket_t *sock, unsigned int backlog) {
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+
+       REQUIRE(!sock->listener);
+       REQUIRE(sock->bound);
+       REQUIRE(sock->type == isc_sockettype_tcp);
+
+       if (backlog == 0)
+               backlog = SOMAXCONN;
+
+       if (listen(sock->fd, (int)backlog) < 0) {
+               UNLOCK(&sock->lock);
+               isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
+
+               UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf);
+
+               return (ISC_R_UNEXPECTED);
+       }
+
+       socket_log(__LINE__, sock, NULL, TRACE,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "listening");
+       sock->listener = 1;
+       _set_state(sock, SOCK_LISTEN);
+
+       UNLOCK(&sock->lock);
+       return (ISC_R_SUCCESS);
+}
+
+/*
+ * This should try to do aggressive accept() XXXMLG
+ */
+isc_result_t
+isc_socket_accept(isc_socket_t *sock,
+                 isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       isc_socket_newconnev_t *adev;
+       isc_socketmgr_t *manager;
+       isc_task_t *ntask = NULL;
+       isc_socket_t *nsock;
+       isc_result_t result;
+       IoCompletionInfo *lpo;
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+
+       REQUIRE(sock->listener);
+
+       /*
+        * Sender field is overloaded here with the task we will be sending
+        * this event to.  Just before the actual event is delivered the
+        * actual ev_sender will be touched up to be the socket.
+        */
+       adev = (isc_socket_newconnev_t *)
+               isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,
+                                  action, arg, sizeof(*adev));
+       if (adev == NULL) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_NOMEMORY);
+       }
+       ISC_LINK_INIT(adev, ev_link);
+
+       result = allocate_socket(manager, sock->type, &nsock);
+       if (result != ISC_R_SUCCESS) {
+               isc_event_free((isc_event_t **)&adev);
+               UNLOCK(&sock->lock);
+               return (result);
+       }
+
+       /*
+        * AcceptEx() requires we pass in a socket.
+        */
+       nsock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP);
+       if (nsock->fd == INVALID_SOCKET) {
+               free_socket(&nsock, __LINE__);
+               isc_event_free((isc_event_t **)&adev);
+               UNLOCK(&sock->lock);
+               return (ISC_R_FAILURE); // XXXMLG need real error message
+       }
+
+       /*
+        * Attach to socket and to task.
+        */
+       isc_task_attach(task, &ntask);
+       nsock->references++;
+
+       adev->ev_sender = ntask;
+       adev->newsocket = nsock;
+       _set_state(nsock, SOCK_ACCEPT);
+
+       /*
+        * Queue io completion for an accept().
+        */
+       lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+                                           HEAP_ZERO_MEMORY,
+                                           sizeof(IoCompletionInfo));
+       RUNTIME_CHECK(lpo != NULL);
+       lpo->acceptbuffer = (void *)HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY,
+               (sizeof(SOCKADDR_STORAGE) + 16) * 2);
+       RUNTIME_CHECK(lpo->acceptbuffer != NULL);
+
+       lpo->adev = adev;
+       lpo->request_type = SOCKET_ACCEPT;
+
+       ISCAcceptEx(sock->fd,
+                   nsock->fd,                          /* Accepted Socket */
+                   lpo->acceptbuffer,                  /* Buffer for initial Recv */
+                   0,                                  /* Length of Buffer */
+                   sizeof(SOCKADDR_STORAGE) + 16,              /* Local address length + 16 */
+                   sizeof(SOCKADDR_STORAGE) + 16,              /* Remote address lengh + 16 */
+                   (LPDWORD)&lpo->received_bytes,      /* Bytes Recved */
+                   (LPOVERLAPPED)lpo                   /* Overlapped structure */
+                   );
+       iocompletionport_update(nsock);
+
+       socket_log(__LINE__, sock, NULL, TRACE,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND,
+                  "accepting for nsock %p fd %d", nsock, nsock->fd);
+
+       /*
+        * Enqueue the event
+        */
+       ISC_LIST_ENQUEUE(sock->accept_list, adev, ev_link);
+       sock->pending_accept++;
+       sock->pending_iocp++;
+
+       UNLOCK(&sock->lock);
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr,
+                  isc_task_t *task, isc_taskaction_t action, const void *arg)
+{
+       char strbuf[ISC_STRERRORSIZE];
+       isc_socket_connev_t *cdev;
+       isc_task_t *ntask = NULL;
+       isc_socketmgr_t *manager;
+       IoCompletionInfo *lpo;
+       int bind_errno;
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(addr != NULL);
+       REQUIRE(task != NULL);
+       REQUIRE(action != NULL);
+
+       manager = sock->manager;
+       REQUIRE(VALID_MANAGER(manager));
+       REQUIRE(addr != NULL);
+
+       if (isc_sockaddr_ismulticast(addr))
+               return (ISC_R_MULTICAST);
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+
+       /*
+        * Windows sockets won't connect unless the socket is bound.
+        */
+       if (!sock->bound) {
+               isc_sockaddr_t any;
+
+               isc_sockaddr_anyofpf(&any, isc_sockaddr_pf(addr));
+               if (bind(sock->fd, &any.type.sa, any.length) < 0) {
+                       bind_errno = WSAGetLastError();
+                       UNLOCK(&sock->lock);
+                       switch (bind_errno) {
+                       case WSAEACCES:
+                               return (ISC_R_NOPERM);
+                       case WSAEADDRNOTAVAIL:
+                               return (ISC_R_ADDRNOTAVAIL);
+                       case WSAEADDRINUSE:
+                               return (ISC_R_ADDRINUSE);
+                       case WSAEINVAL:
+                               return (ISC_R_BOUND);
+                       default:
+                               isc__strerror(bind_errno, strbuf,
+                                             sizeof(strbuf));
+                               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                                "bind: %s", strbuf);
+                               return (ISC_R_UNEXPECTED);
+                       }
+               }
+               sock->bound = 1;
+       }
+
+       REQUIRE(!sock->pending_connect);
+
+       cdev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
+                                                       ISC_SOCKEVENT_CONNECT,
+                                                       action, arg,
+                                                       sizeof(*cdev));
+       if (cdev == NULL) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_NOMEMORY);
+       }
+       ISC_LINK_INIT(cdev, ev_link);
+
+       if (sock->type == isc_sockettype_tcp) {
+               /*
+                * Queue io completion for an accept().
+                */
+               lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+                                                   HEAP_ZERO_MEMORY,
+                                                   sizeof(IoCompletionInfo));
+               lpo->cdev = cdev;
+               lpo->request_type = SOCKET_CONNECT;
+
+               sock->address = *addr;
+               ISCConnectEx(sock->fd, &addr->type.sa, addr->length,
+                       NULL, 0, NULL, (LPOVERLAPPED)lpo);
+
+               /*
+                * Attach to task.
+                */
+               isc_task_attach(task, &ntask);
+               cdev->ev_sender = ntask;
+
+               sock->pending_connect = 1;
+               _set_state(sock, SOCK_CONNECT);
+
+               /*
+                * Enqueue the request.
+                */
+               sock->connect_ev = cdev;
+               sock->pending_iocp++;
+       } else {
+               WSAConnect(sock->fd, &addr->type.sa, addr->length, NULL, NULL, NULL, NULL);
+               cdev->result = ISC_R_SUCCESS;
+               isc_task_send(task, (isc_event_t **)&cdev);
+       }
+       CONSISTENT(sock);
+       UNLOCK(&sock->lock);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+       isc_result_t result;
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(addressp != NULL);
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+
+       if (sock->connected) {
+               *addressp = sock->address;
+               result = ISC_R_SUCCESS;
+       } else {
+               result = ISC_R_NOTCONNECTED;
+       }
+
+       UNLOCK(&sock->lock);
+
+       return (result);
+}
+
+isc_result_t
+isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+       ISC_SOCKADDR_LEN_T len;
+       isc_result_t result;
+       char strbuf[ISC_STRERRORSIZE];
+
+       REQUIRE(VALID_SOCKET(sock));
+       REQUIRE(addressp != NULL);
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+
+       if (!sock->bound) {
+               result = ISC_R_NOTBOUND;
+               goto out;
+       }
+
+       result = ISC_R_SUCCESS;
+
+       len = sizeof(addressp->type);
+       if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
+               isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s",
+                                strbuf);
+               result = ISC_R_UNEXPECTED;
+               goto out;
+       }
+       addressp->length = (unsigned int)len;
+
+ out:
+       UNLOCK(&sock->lock);
+
+       return (result);
+}
+
+/*
+ * Run through the list of events on this socket, and cancel the ones
+ * queued for task "task" of type "how".  "how" is a bitmask.
+ */
+void
+isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       /*
+        * Quick exit if there is nothing to do.  Don't even bother locking
+        * in this case.
+        */
+       if (how == 0)
+               return;
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return;
+       }
+
+       /*
+        * All of these do the same thing, more or less.
+        * Each will:
+        *      o If the internal event is marked as "posted" try to
+        *        remove it from the task's queue.  If this fails, mark it
+        *        as canceled instead, and let the task clean it up later.
+        *      o For each I/O request for that task of that type, post
+        *        its done event with status of "ISC_R_CANCELED".
+        *      o Reset any state needed.
+        */
+
+       if ((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV) {
+               isc_socketevent_t      *dev;
+               isc_socketevent_t      *next;
+               isc_task_t             *current_task;
+
+               dev = ISC_LIST_HEAD(sock->recv_list);
+               while (dev != NULL) {
+                       current_task = dev->ev_sender;
+                       next = ISC_LIST_NEXT(dev, ev_link);
+                       if ((task == NULL) || (task == current_task)) {
+                               dev->result = ISC_R_CANCELED;
+                               send_recvdone_event(sock, &dev);
+                       }
+                       dev = next;
+               }
+       }
+       how &= ~ISC_SOCKCANCEL_RECV;
+
+       if ((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND) {
+               isc_socketevent_t      *dev;
+               isc_socketevent_t      *next;
+               isc_task_t             *current_task;
+
+               dev = ISC_LIST_HEAD(sock->send_list);
+
+               while (dev != NULL) {
+                       current_task = dev->ev_sender;
+                       next = ISC_LIST_NEXT(dev, ev_link);
+                       if ((task == NULL) || (task == current_task)) {
+                               dev->result = ISC_R_CANCELED;
+                               send_senddone_event(sock, &dev);
+                       }
+                       dev = next;
+               }
+       }
+       how &= ~ISC_SOCKCANCEL_SEND;
+
+       if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT)
+           && !ISC_LIST_EMPTY(sock->accept_list)) {
+               isc_socket_newconnev_t *dev;
+               isc_socket_newconnev_t *next;
+               isc_task_t             *current_task;
+
+               dev = ISC_LIST_HEAD(sock->accept_list);
+               while (dev != NULL) {
+                       current_task = dev->ev_sender;
+                       next = ISC_LIST_NEXT(dev, ev_link);
+
+                       if ((task == NULL) || (task == current_task)) {
+
+                               dev->newsocket->references--;
+                               closesocket(dev->newsocket->fd);
+                               dev->newsocket->fd = INVALID_SOCKET;
+                               free_socket(&dev->newsocket, __LINE__);
+
+                               dev->result = ISC_R_CANCELED;
+                               send_acceptdone_event(sock, &dev);
+                       }
+
+                       dev = next;
+               }
+       }
+       how &= ~ISC_SOCKCANCEL_ACCEPT;
+
+       /*
+        * Connecting is not a list.
+        */
+       if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT)
+           && sock->connect_ev != NULL) {
+               isc_socket_connev_t    *dev;
+               isc_task_t             *current_task;
+
+               INSIST(sock->pending_connect);
+
+               dev = sock->connect_ev;
+               current_task = dev->ev_sender;
+
+               if ((task == NULL) || (task == current_task)) {
+                       closesocket(sock->fd);
+                       sock->fd = INVALID_SOCKET;
+                       _set_state(sock, SOCK_CLOSED);
+
+                       sock->connect_ev = NULL;
+                       dev->result = ISC_R_CANCELED;
+                       send_connectdone_event(sock, &dev);
+               }
+       }
+       how &= ~ISC_SOCKCANCEL_CONNECT;
+
+       maybe_free_socket(&sock, __LINE__);
+}
+
+isc_sockettype_t
+isc_socket_gettype(isc_socket_t *sock) {
+       isc_sockettype_t type;
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_R_CONNREFUSED);
+       }
+
+       type = sock->type;
+       UNLOCK(&sock->lock);
+       return (type);
+}
+
+isc_boolean_t
+isc_socket_isbound(isc_socket_t *sock) {
+       isc_boolean_t val;
+
+       REQUIRE(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       CONSISTENT(sock);
+
+       /*
+        * make sure that the socket's not closed
+        */
+       if (sock->fd == INVALID_SOCKET) {
+               UNLOCK(&sock->lock);
+               return (ISC_FALSE);
+       }
+
+       val = ((sock->bound) ? ISC_TRUE : ISC_FALSE);
+       UNLOCK(&sock->lock);
+
+       return (val);
+}
+
+void
+isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) {
+#if defined(IPV6_V6ONLY)
+       int onoff = yes ? 1 : 0;
+#else
+       UNUSED(yes);
+#endif
+
+       REQUIRE(VALID_SOCKET(sock));
+
+#ifdef IPV6_V6ONLY
+       if (sock->pf == AF_INET6) {
+               (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+                                (void *)&onoff, sizeof(onoff));
+       }
+#endif
+}
+
+void
+isc_socket_cleanunix(isc_sockaddr_t *addr, isc_boolean_t active) {
+       UNUSED(addr);
+       UNUSED(active);
+}
+
+isc_result_t
+isc_socket_permunix(isc_sockaddr_t *addr, isc_uint32_t perm,
+                   isc_uint32_t owner, isc_uint32_t group)
+{
+       UNUSED(addr);
+       UNUSED(perm);
+       UNUSED(owner);
+       UNUSED(group);
+       return (ISC_R_NOTIMPLEMENTED);
+}
+
+void
+isc_socket_setname(isc_socket_t *socket, const char *name, void *tag) {
+
+       /*
+        * Name 'socket'.
+        */
+
+       REQUIRE(VALID_SOCKET(socket));
+
+       LOCK(&socket->lock);
+       memset(socket->name, 0, sizeof(socket->name));
+       strncpy(socket->name, name, sizeof(socket->name) - 1);
+       socket->tag = tag;
+       UNLOCK(&socket->lock);
+}
+
+const char *
+isc_socket_getname(isc_socket_t *socket) {
+       return (socket->name);
+}
+
+void *
+isc_socket_gettag(isc_socket_t *socket) {
+       return (socket->tag);
+}
+
+void
+isc__socketmgr_setreserved(isc_socketmgr_t *manager, isc_uint32_t reserved) {
+       UNUSED(manager);
+       UNUSED(reserved);
+}
diff --git a/lib/isc/win32/stdio.c b/lib/isc/win32/stdio.c
new file mode 100644 (file)
index 0000000..427a8e1
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stdio.c,v 1.6 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <config.h>
+
+#include <io.h>
+#include <errno.h>
+
+#include <isc/stdio.h>
+
+#include "errno2result.h"
+
+isc_result_t
+isc_stdio_open(const char *filename, const char *mode, FILE **fp) {
+       FILE *f;
+
+       f = fopen(filename, mode);
+       if (f == NULL)
+               return (isc__errno2result(errno));
+       *fp = f;
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_stdio_close(FILE *f) {
+       int r;
+
+       r = fclose(f);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_seek(FILE *f, long offset, int whence) {
+       int r;
+
+       r = fseek(f, offset, whence);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, size_t *nret) {
+       isc_result_t result = ISC_R_SUCCESS;
+       size_t r;
+
+       clearerr(f);
+       r = fread(ptr, size, nmemb, f);
+       if (r != nmemb) {
+               if (feof(f))
+                       result = ISC_R_EOF;
+               else
+                       result = isc__errno2result(errno);
+       }
+       if (nret != NULL)
+               *nret = r;
+       return (result);
+}
+
+isc_result_t
+isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f,
+              size_t *nret)
+{
+       isc_result_t result = ISC_R_SUCCESS;
+       size_t r;
+
+       clearerr(f);
+       r = fwrite(ptr, size, nmemb, f);
+       if (r != nmemb)
+               result = isc__errno2result(errno);
+       if (nret != NULL)
+               *nret = r;
+       return (result);
+}
+
+isc_result_t
+isc_stdio_flush(FILE *f) {
+       int r;
+
+       r = fflush(f);
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
+isc_result_t
+isc_stdio_sync(FILE *f) {
+       int r;
+
+       r = _commit(_fileno(f));
+       if (r == 0)
+               return (ISC_R_SUCCESS);
+       else
+               return (isc__errno2result(errno));
+}
+
diff --git a/lib/isc/win32/stdtime.c b/lib/isc/win32/stdtime.c
new file mode 100644 (file)
index 0000000..574297e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: stdtime.c,v 1.12 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <config.h>
+
+#include <time.h>
+
+#include <isc/assertions.h>
+#include <isc/stdtime.h>
+#include <isc/util.h>
+
+void
+isc_stdtime_get(isc_stdtime_t *t) {
+       /*
+        * Set 't' to the number of seconds past 00:00:00 UTC, January 1, 1970.
+        */
+
+       REQUIRE(t != NULL);
+
+       (void)time(t);
+}
index c5883caa7aea7c12910df0e5c267652a25fbfbc4..41743328a430dcc2bddd199685c6bb8586d65a30 100644 (file)
@@ -1,55 +1,33 @@
 /*
- * Copyright (C) 2002  Internet Software Consortium.
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001, 2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* From BIND 9 lib/isc/win32/: strerror.c,v 1.5 2002/08/01 03:52:14 mayer */
+/* $Id: strerror.c,v 1.8 2007/06/19 23:47:19 tbox Exp $ */
 
-/*
- * We don't need this warning message
- */
-#pragma warning(disable: 4127) /* conditional expression is constant */
+#include <config.h>
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
 #include <stdio.h>
 #include <string.h>
-#include <windows.h>
-#include <isc/list.h>
-#include "ntp_stdlib.h"
-
-
-/*
- * Messsage list
- */
-typedef struct msg_list msg_list_t;
-
-struct msg_list {
-       int code;
-       char *msg;
-       ISC_LINK(msg_list_t) link;
-};
-
-static ISC_LIST(msg_list_t) errormsg_list;
+#include <winsock2.h>
 
-BOOL initialized = FALSE;
-
-static CRITICAL_SECTION ErrorMsgLock;
-# define LOCK(lock)    EnterCriticalSection(lock)
-# define UNLOCK(lock)  LeaveCriticalSection(lock)
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/strerror.h>
+#include <isc/util.h>
 
 /*
  * Forward declarations
@@ -61,26 +39,18 @@ FormatError(int error);
 char *
 GetWSAErrorMessage(int errval);
 
-static char *
-isc__NTstrerror(int err);
+char *
+NTstrerror(int err, BOOL *bfreebuf);
 
 /*
- * Initialize the error message list
+ * We need to do this this way for profiled locks.
  */
 
-void
-initialize() {
-       ISC_LIST_INIT(errormsg_list);
-       InitializeCriticalSection(&ErrorMsgLock);
-       initialized = TRUE;
+static isc_mutex_t isc_strerror_lock;
+static void init_lock(void) {
+       RUNTIME_CHECK(isc_mutex_init(&isc_strerror_lock) == ISC_R_SUCCESS);
 }
 
-char *
-NTstrerror(int errnum) {
-       if(!initialized)
-               initialize();
-       return (isc__NTstrerror(errnum));
-}
 /*
  * This routine needs to free up any buffer allocated by FormatMessage
  * if that routine gets used.
@@ -89,73 +59,36 @@ NTstrerror(int errnum) {
 void
 isc__strerror(int num, char *buf, size_t size) {
        char *msg;
+       BOOL freebuf;
        unsigned int unum = num;
-       if(!initialized)
-               initialize();
+       static isc_once_t once = ISC_ONCE_INIT;
 
-       msg = isc__NTstrerror(num);
-       /*
-        * C4996 is strncpy, _snprintf may be unsafe, consider
-        * strncpy_s, _snprintf_s instead
-        * Those _s routines are not available with older MS
-        * compilers and our paranoid uses are safe.  An
-        * alternative would be to use the _s versions for
-        * newer compilers instead of disabling warning 4996.
-        */
-       #if defined(_MSC_VER)
-               #pragma warning(push)
-               #pragma warning(disable: 4996)
-       #endif /* _MSC_VER */
-
-       /* 
-        * Both strncpy and _snprintf will not null terminate in the
-        * edge case of the message fitting but the terminator not.
-        * This seems to be a MS-specific behavior, but our paranoid
-        * approach should be harmless on less challenged runtimes.
-        */
-       if (msg != NULL) {
-               strncpy(buf, msg, size - 1);
-       } else {
-               _snprintf(buf, size - 1, "Unknown error: %u", unum);
-       }
-       buf[size - 1] = '\0';
+       REQUIRE(buf != NULL);
+
+       RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS);
 
-       #if defined(_MSC_VER)
-               #pragma warning(pop)
-       #endif /* _MSC_VER */
+       LOCK(&isc_strerror_lock);
+       freebuf = FALSE;
+       msg = NTstrerror(num, &freebuf);
+       if (msg != NULL)
+               snprintf(buf, size, "%s", msg);
+       else
+               snprintf(buf, size, "Unknown error: %u", unum);
+       if(freebuf && msg != NULL) {
+               LocalFree(msg);
+       }
+       UNLOCK(&isc_strerror_lock);
 }
 
 /*
- * FormatError returns a message string for a given error code.
- * Callers should not attempt to free the string, as it is cached
- * and used again.
+ * Note this will cause a memory leak unless the memory allocated here
+ * is freed by calling LocalFree.  isc__strerror does this before unlocking.
+ * This only gets called if there is a system type of error and will likely
+ * be an unusual event.
  */
 char *
 FormatError(int error) {
        LPVOID lpMsgBuf = NULL;
-
-       msg_list_t *lmsg; 
-
-       /*
-        * See if we already have the error code
-        */
-
-       LOCK(&ErrorMsgLock);
-
-       lmsg = ISC_LIST_HEAD(errormsg_list);
-       while (lmsg != NULL) {
-               if (lmsg->code == error) {
-                       lpMsgBuf = lmsg->msg;
-                       UNLOCK(&ErrorMsgLock);
-                       return (lpMsgBuf);
-               }
-               lmsg = ISC_LIST_NEXT(lmsg, link);
-       }
-
-       /*
-        * Not found
-        */
-
        FormatMessage( 
                FORMAT_MESSAGE_ALLOCATE_BUFFER | 
                FORMAT_MESSAGE_FROM_SYSTEM | 
@@ -168,121 +101,39 @@ FormatError(int error) {
                0,
                NULL); 
 
-       if (lpMsgBuf) {
-               lmsg = emalloc(sizeof(*lmsg));
-               lmsg->code = error;
-               lmsg->msg = lpMsgBuf;
-               ISC_LIST_APPEND(errormsg_list, lmsg, link);
-       }
-       UNLOCK(&ErrorMsgLock);
        return (lpMsgBuf);
 }
 
 /*
- * Free the memory allocated for error messages during shutdown to
- * increase the utility of _DEBUG MS CRT's malloc leak checks.
- *
- * ntservice_exit() calls this routine during shutdown.  (ntservice.c)
+ * This routine checks the error value and calls the WSA Windows Sockets
+ * Error message function GetWSAErrorMessage below if it's within that range
+ * since those messages are not available in the system error messages.
  */
-#ifdef _DEBUG
-void
-FormatErrorFreeMem(void) {
-       msg_list_t *entry;
-       /*
-        * Delete the lock used to protect the error message list as
-        * a cheap way of catching FormatError calls after this
-        * routine has torn things down for termination.
-        */
-       DeleteCriticalSection(&ErrorMsgLock);
-
-       entry = ISC_LIST_HEAD(errormsg_list);
-       while (entry) {
-               ISC_LIST_DEQUEUE(errormsg_list, entry, link);
-               
-               /* Memory from FormatMessage goes back via LocalFree */
-               LocalFree(entry->msg);
-               free(entry);
+char *
+NTstrerror(int err, BOOL *bfreebuf) {
+       char *retmsg = NULL;
 
-               entry = ISC_LIST_HEAD(errormsg_list);
-       }
-}
-#endif /* _DEBUG */
+       /* Copy the error value first in case of other errors */        
+       DWORD errval = err; 
 
-/*
- * This routine checks the error value and calls the WSA Windows
- * Sockets Error message function GetWSAErrorMessage below if it's
- * within that range since those messages are not available in the
- * system error messages in Windows NT 4 and earlier Windows.  With
- * Windows 2000 and later, FormatMessage will translate socket errors,
- * so GetWSAErrorMessage can be removed once Windows NT is no longer
- * supported at runtime.
- */
-static char *
-isc__NTstrerror(int err) {
-       char *retmsg = NULL;
+       *bfreebuf = FALSE;
 
        /* Get the Winsock2 error messages */
-       if (err >= WSABASEERR && err <= (WSABASEERR + 1015)) {
-               retmsg = GetWSAErrorMessage(err);
-       }
-       /*
-        * C4996 here is strerror may be unsafe, consider
-        * strerror_s instead.
-        * strerror_s copies the message into a caller-supplied buffer,
-        * which is not an option when providing a strerror() wrapper.
-        */
-       #if defined(_MSC_VER)
-               #pragma warning(push)
-               #pragma warning(disable: 4996)
-       #endif /* _MSC_VER */
-
-       if (!retmsg) {
-#undef strerror
-               retmsg = strerror(err);
-       }
-
-       #if defined(_MSC_VER)
-               #pragma warning(pop)
-       #endif /* _MSC_VER */
-
-       if (!retmsg) {
-               /*
-                * Handle a few errno values MS strerror() doesn't,
-                * since they only generate a subset of errno values
-                * in the C runtime.  These are used by RFC 2783
-                * PPSAPI timepps.h functions in ntpd on Windows.
-                */
-
-               #ifndef ENXIO
-               #define ENXIO           6
-               #endif
-
-               #ifndef EOPNOTSUPP
-               #define EOPNOTSUPP      45
-               #endif
-
-               switch (err) {
-                   case ENXIO:
-                       retmsg = "Device not configured";
-                       break;
-
-                   case EOPNOTSUPP:
-                       retmsg = "Operation not supported";
-                       break;
-               }
+       if (errval >= WSABASEERR && errval <= (WSABASEERR + 1015)) {
+               retmsg = GetWSAErrorMessage(errval);
+               if (retmsg != NULL)
+                       return (retmsg);
        }
        /*
-        * Handle Windows GetLastError error codes.  Note that some
-        * low-numbered Windows error codes conflict with the errno
-        * space and this routine will return the errno-related text
-        * in preference to the GetLastError/FormatMessage text for
-        * those conflicting values.
+        * If it's not one of the standard Unix error codes,
+        * try a system error message
         */
-       if (!retmsg) {
-               retmsg = FormatError(err);
+       if (errval > (DWORD) _sys_nerr) {
+               *bfreebuf = TRUE;
+               return (FormatError(errval));
+       } else {
+               return (strerror(errval));
        }
-
-       return (retmsg);
 }
 
 /*
@@ -292,15 +143,15 @@ void __cdecl
 NTperror(char *errmsg) {
        /* Copy the error value first in case of other errors */
        int errval = errno; 
+       BOOL bfreebuf = FALSE;
        char *msg;
-       if(!initialized)
-               initialize();
 
-       msg = isc__NTstrerror(errval);
-       if (!msg) {
-               msg = "unrecognized errno";
-       }
+       msg = NTstrerror(errval, &bfreebuf);
        fprintf(stderr, "%s: %s\n", errmsg, msg);
+       if(bfreebuf == TRUE) {
+               LocalFree(msg);
+       }
+
 }
 
 /*
@@ -517,7 +368,6 @@ GetWSAErrorMessage(int errval) {
        return (msg);
 }
 
-#ifdef NTP_DEAD_CODE_GetCryptErrorMessage
 /*
  * These error messages are more informative about CryptAPI Errors than the
  * standard error messages
@@ -606,4 +456,4 @@ GetCryptErrorMessage(int errval) {
        }
        return msg;
 }
-#endif
+
diff --git a/lib/isc/win32/syslog.c b/lib/isc/win32/syslog.c
new file mode 100644 (file)
index 0000000..375784f
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001-2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: syslog.c,v 1.10 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <windows.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <isc/bindevt.h>
+#include <isc/result.h>
+#include <isc/syslog.h>
+#include <isc/util.h>
+
+static HANDLE hAppLog = NULL;
+static FILE *log_stream;
+static int debug_level = 0;
+
+static struct dsn_c_pvt_sfnt {
+       int val;
+       const char *strval;
+} facilities[] = {
+       { LOG_KERN,             "kern" },
+       { LOG_USER,             "user" },
+       { LOG_MAIL,             "mail" },
+       { LOG_DAEMON,           "daemon" },
+       { LOG_AUTH,             "auth" },
+       { LOG_SYSLOG,           "syslog" },
+       { LOG_LPR,              "lpr" },
+#ifdef LOG_NEWS
+       { LOG_NEWS,             "news" },
+#endif
+#ifdef LOG_UUCP
+       { LOG_UUCP,             "uucp" },
+#endif
+#ifdef LOG_CRON
+       { LOG_CRON,             "cron" },
+#endif
+#ifdef LOG_AUTHPRIV
+       { LOG_AUTHPRIV,         "authpriv" },
+#endif
+#ifdef LOG_FTP
+       { LOG_FTP,              "ftp" },
+#endif
+       { LOG_LOCAL0,           "local0"},
+       { LOG_LOCAL1,           "local1"},
+       { LOG_LOCAL2,           "local2"},
+       { LOG_LOCAL3,           "local3"},
+       { LOG_LOCAL4,           "local4"},
+       { LOG_LOCAL5,           "local5"},
+       { LOG_LOCAL6,           "local6"},
+       { LOG_LOCAL7,           "local7"},
+       { 0,                    NULL }
+};
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp) {
+       int i;
+
+       REQUIRE(str != NULL);
+       REQUIRE(facilityp != NULL);
+
+       for (i = 0; facilities[i].strval != NULL; i++) {
+               if (strcasecmp(facilities[i].strval, str) == 0) {
+                       *facilityp = facilities[i].val;
+                       return (ISC_R_SUCCESS);
+               }
+       }
+       return (ISC_R_NOTFOUND);
+}
+
+/*
+ * Log to the NT Event Log
+ */
+void
+syslog(int level, const char *fmt, ...) {
+       va_list ap;
+       char buf[1024];
+       char *str[1];
+
+       str[0] = buf;
+
+       va_start(ap, fmt);
+       vsprintf(buf, fmt, ap);
+       va_end(ap);
+
+       /* Make sure that the channel is open to write the event */
+       if (hAppLog != NULL) {
+               switch (level) {
+               case LOG_INFO:
+               case LOG_NOTICE:
+               case LOG_DEBUG:
+                       ReportEvent(hAppLog, EVENTLOG_INFORMATION_TYPE, 0,
+                                   BIND_INFO_MSG, NULL, 1, 0, str, NULL);
+                       break;
+               case LOG_WARNING:
+                       ReportEvent(hAppLog, EVENTLOG_WARNING_TYPE, 0,
+                                   BIND_WARN_MSG, NULL, 1, 0, str, NULL);
+                       break;
+               default:
+                       ReportEvent(hAppLog, EVENTLOG_ERROR_TYPE, 0,
+                                   BIND_ERR_MSG, NULL, 1, 0, str, NULL);
+                       break;
+               }
+       }
+}
+
+/*
+ * Initialize event logging
+ */
+void
+openlog(const char *name, int flags, ...) {
+       /* Get a handle to the Application event log */
+       hAppLog = RegisterEventSource(NULL, name);
+}
+
+/*
+ * Close the Handle to the application Event Log
+ * We don't care whether or not we succeeded so ignore return values
+ * In fact if we failed then we would have nowhere to put the message
+ */
+void
+closelog() {
+       DeregisterEventSource(hAppLog);
+}
+
+/*
+ * Keep event logging synced with the current debug level
+ */
+void
+ModifyLogLevel(int level) {
+       debug_level = level;    
+}
+
+/*
+ * Initialize logging for the port section of libbind.
+ * Piggyback onto stream given.
+ */
+void
+InitNTLogging(FILE *stream, int debug) {
+       log_stream = stream;
+       ModifyLogLevel(debug);
+}
+/*
+ * This function is for reporting errors to the application
+ * event log in case the regular syslog is not available
+ * mainly during startup. It should not be used under normal
+ * circumstances.
+ */
+void
+NTReportError(const char *name, const char *str) {
+       HANDLE hNTAppLog = NULL;
+       const char *buf[1];
+
+       buf[0] = str;
+
+       hNTAppLog = RegisterEventSource(NULL, name);
+
+       ReportEvent(hNTAppLog, EVENTLOG_ERROR_TYPE, 0,
+                   BIND_ERR_MSG, NULL, 1, 0, buf, NULL);
+
+       DeregisterEventSource(hNTAppLog);
+}
diff --git a/lib/isc/win32/syslog.h b/lib/isc/win32/syslog.h
new file mode 100644 (file)
index 0000000..fd4b3a6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001, 2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: syslog.h,v 1.7 2007/06/19 23:47:19 tbox Exp $ */
+
+#ifndef _SYSLOG_H
+#define _SYSLOG_H
+
+#include <stdio.h>
+
+/* Constant definitions for openlog() */
+#define LOG_PID                1
+#define LOG_CONS       2
+/* NT event log does not support facility level */
+#define LOG_KERN       0
+#define LOG_USER       0
+#define LOG_MAIL       0
+#define LOG_DAEMON     0
+#define LOG_AUTH       0
+#define LOG_SYSLOG     0
+#define LOG_LPR                0
+#define LOG_LOCAL0     0
+#define LOG_LOCAL1     0
+#define LOG_LOCAL2     0
+#define LOG_LOCAL3     0
+#define LOG_LOCAL4     0
+#define LOG_LOCAL5     0
+#define LOG_LOCAL6     0
+#define LOG_LOCAL7     0
+
+#define LOG_EMERG       0       /* system is unusable */
+#define LOG_ALERT       1       /* action must be taken immediately */
+#define LOG_CRIT        2       /* critical conditions */
+#define LOG_ERR         3       /* error conditions */
+#define LOG_WARNING     4       /* warning conditions */
+#define LOG_NOTICE      5       /* normal but signification condition */
+#define LOG_INFO        6       /* informational */
+#define LOG_DEBUG       7       /* debug-level messages */
+
+void
+syslog(int level, const char *fmt, ...);
+
+void
+openlog(const char *, int, ...);
+
+void
+closelog(void);
+
+void
+ModifyLogLevel(int level);
+
+void
+InitNTLogging(FILE *, int);
+
+void
+NTReportError(const char *, const char *);
+/*
+ * Include the event codes required for logging.
+ */
+#include <isc/bindevt.h>
+
+#endif
diff --git a/lib/isc/win32/thread.c b/lib/isc/win32/thread.c
new file mode 100644 (file)
index 0000000..be955ea
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: thread.c,v 1.24 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <config.h>
+
+#include <process.h>
+
+#include <isc/thread.h>
+
+isc_result_t
+isc_thread_create(isc_threadfunc_t start, isc_threadarg_t arg,
+                 isc_thread_t *threadp)
+{
+       isc_thread_t thread;
+       unsigned int id;
+
+       thread = (isc_thread_t)_beginthreadex(NULL, 0, start, arg, 0, &id);
+       if (thread == NULL) {
+               /* XXX */
+               return (ISC_R_UNEXPECTED);
+       }
+
+       *threadp = thread;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_thread_join(isc_thread_t thread, isc_threadresult_t *rp) {
+       DWORD result;
+
+       result = WaitForSingleObject(thread, INFINITE);
+       if (result != WAIT_OBJECT_0) {
+               /* XXX */
+               return (ISC_R_UNEXPECTED);
+       }
+       if (rp != NULL && !GetExitCodeThread(thread, rp)) {
+               /* XXX */
+               return (ISC_R_UNEXPECTED);
+       }
+       (void)CloseHandle(thread);
+
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_thread_setconcurrency(unsigned int level) {
+       /*
+        * This is unnecessary on Win32 systems, but is here so that the
+        * call exists
+        */
+}
+
+void *
+isc_thread_key_getspecific(isc_thread_key_t key) {
+       return(TlsGetValue(key));
+}
+
+int
+isc_thread_key_setspecific(isc_thread_key_t key, void *value) {
+       return (TlsSetValue(key, value) ? 0 : GetLastError());
+}
+
+int
+isc_thread_key_create(isc_thread_key_t *key, void (*func)(void *)) {
+       *key = TlsAlloc();
+
+       return ((*key != -1) ? 0 : GetLastError());
+}
+
+int
+isc_thread_key_delete(isc_thread_key_t key) {
+       return (TlsFree(key) ? 0 : GetLastError());
+}
diff --git a/lib/isc/win32/time.c b/lib/isc/win32/time.c
new file mode 100644 (file)
index 0000000..aebf73d
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2004, 2006-2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: time.c,v 1.48 2008/09/08 23:47:10 tbox Exp $ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <windows.h>
+
+#include <isc/assertions.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+/*
+ * struct FILETIME uses "100-nanoseconds intervals".
+ * NS / S = 1000000000 (10^9).
+ * While it is reasonably obvious that this makes the needed
+ * conversion factor 10^7, it is coded this way for additional clarity.
+ */
+#define NS_PER_S       1000000000
+#define NS_INTERVAL    100
+#define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL)
+#define UINT64_MAX     _UI64_MAX
+
+/***
+ *** Absolute Times
+ ***/
+
+static isc_time_t epoch = { { 0, 0 } };
+LIBISC_EXTERNAL_DATA isc_time_t *isc_time_epoch = &epoch;
+
+/***
+ *** Intervals
+ ***/
+
+static isc_interval_t zero_interval = { 0 };
+LIBISC_EXTERNAL_DATA isc_interval_t *isc_interval_zero = &zero_interval;
+
+void
+isc_interval_set(isc_interval_t *i, unsigned int seconds,
+                unsigned int nanoseconds)
+{
+       REQUIRE(i != NULL);
+       REQUIRE(nanoseconds < NS_PER_S);
+
+       /*
+        * This rounds nanoseconds up not down.
+        */
+       i->interval = (LONGLONG)seconds * INTERVALS_PER_S
+               + (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL;
+}
+
+isc_boolean_t
+isc_interval_iszero(const isc_interval_t *i) {
+       REQUIRE(i != NULL);
+       if (i->interval == 0)
+               return (ISC_TRUE);
+
+       return (ISC_FALSE);
+}
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
+       SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 };
+       FILETIME temp;
+       ULARGE_INTEGER i1;
+
+       REQUIRE(t != NULL);
+       REQUIRE(nanoseconds < NS_PER_S);
+
+       SystemTimeToFileTime(&epoch, &temp);
+
+       i1.LowPart = t->absolute.dwLowDateTime;
+       i1.HighPart = t->absolute.dwHighDateTime;
+
+       i1.QuadPart += (unsigned __int64)nanoseconds/100;
+       i1.QuadPart += (unsigned __int64)seconds*10000000;
+
+       t->absolute.dwLowDateTime = i1.LowPart;
+       t->absolute.dwHighDateTime = i1.HighPart;
+}
+
+void
+isc_time_settoepoch(isc_time_t *t) {
+       REQUIRE(t != NULL);
+
+       t->absolute.dwLowDateTime = 0;
+       t->absolute.dwHighDateTime = 0;
+}
+
+isc_boolean_t
+isc_time_isepoch(const isc_time_t *t) {
+       REQUIRE(t != NULL);
+
+       if (t->absolute.dwLowDateTime == 0 &&
+           t->absolute.dwHighDateTime == 0)
+               return (ISC_TRUE);
+
+       return (ISC_FALSE);
+}
+
+isc_result_t
+isc_time_now(isc_time_t *t) {
+       REQUIRE(t != NULL);
+
+       GetSystemTimeAsFileTime(&t->absolute);
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
+       ULARGE_INTEGER i1;
+
+       REQUIRE(t != NULL);
+       REQUIRE(i != NULL);
+
+       GetSystemTimeAsFileTime(&t->absolute);
+
+       i1.LowPart = t->absolute.dwLowDateTime;
+       i1.HighPart = t->absolute.dwHighDateTime;
+
+       if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval)
+               return (ISC_R_RANGE);
+
+       i1.QuadPart += i->interval;
+
+       t->absolute.dwLowDateTime  = i1.LowPart;
+       t->absolute.dwHighDateTime = i1.HighPart;
+
+       return (ISC_R_SUCCESS);
+}
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
+       REQUIRE(t1 != NULL && t2 != NULL);
+
+       return ((int)CompareFileTime(&t1->absolute, &t2->absolute));
+}
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
+{
+       ULARGE_INTEGER i1;
+
+       REQUIRE(t != NULL && i != NULL && result != NULL);
+
+       i1.LowPart = t->absolute.dwLowDateTime;
+       i1.HighPart = t->absolute.dwHighDateTime;
+
+       if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval)
+               return (ISC_R_RANGE);
+
+       i1.QuadPart += i->interval;
+
+       result->absolute.dwLowDateTime = i1.LowPart;
+       result->absolute.dwHighDateTime = i1.HighPart;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+                 isc_time_t *result) {
+       ULARGE_INTEGER i1;
+
+       REQUIRE(t != NULL && i != NULL && result != NULL);
+
+       i1.LowPart = t->absolute.dwLowDateTime;
+       i1.HighPart = t->absolute.dwHighDateTime;
+
+       if (i1.QuadPart < (unsigned __int64) i->interval)
+               return (ISC_R_RANGE);
+
+       i1.QuadPart -= i->interval;
+
+       result->absolute.dwLowDateTime = i1.LowPart;
+       result->absolute.dwHighDateTime = i1.HighPart;
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
+       ULARGE_INTEGER i1, i2;
+       LONGLONG i3;
+
+       REQUIRE(t1 != NULL && t2 != NULL);
+
+       i1.LowPart  = t1->absolute.dwLowDateTime;
+       i1.HighPart = t1->absolute.dwHighDateTime;
+       i2.LowPart  = t2->absolute.dwLowDateTime;
+       i2.HighPart = t2->absolute.dwHighDateTime;
+
+       if (i1.QuadPart <= i2.QuadPart)
+               return (0);
+
+       /*
+        * Convert to microseconds.
+        */
+       i3 = (i1.QuadPart - i2.QuadPart) / 10;
+
+       return (i3);
+}
+
+isc_uint32_t
+isc_time_seconds(const isc_time_t *t) {
+       SYSTEMTIME st;
+
+       /*
+        * Convert the time to a SYSTEMTIME structure and the grab the
+        * milliseconds
+        */
+       FileTimeToSystemTime(&t->absolute, &st);
+
+       return ((isc_uint32_t)(st.wMilliseconds / 1000));
+}
+
+isc_uint32_t
+isc_time_nanoseconds(const isc_time_t *t) {
+       SYSTEMTIME st;
+
+       /*
+        * Convert the time to a SYSTEMTIME structure and the grab the
+        * milliseconds
+        */
+       FileTimeToSystemTime(&t->absolute, &st);
+
+       return ((isc_uint32_t)(st.wMilliseconds * 1000000));
+}
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+       FILETIME localft;
+       SYSTEMTIME st;
+       char DateBuf[50];
+       char TimeBuf[50];
+
+       static const char badtime[] = "99-Bad-9999 99:99:99.999";
+
+       REQUIRE(len > 0);
+       if (FileTimeToLocalFileTime(&t->absolute, &localft) &&
+           FileTimeToSystemTime(&localft, &st)) {
+               GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy",
+                             DateBuf, 50);
+               GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER|
+                             TIME_FORCE24HOURFORMAT, &st, NULL, TimeBuf, 50);
+
+               snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf,
+                        st.wMilliseconds);
+
+       } else
+               snprintf(buf, len, badtime);
+}
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+       SYSTEMTIME st;
+       char DateBuf[50];
+       char TimeBuf[50];
+
+       REQUIRE(len > 0);
+       if (FileTimeToSystemTime(&t->absolute, &st)) {
+               GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "ddd',', dd-MMM-yyyy",
+                             DateBuf, 50);
+               GetTimeFormat(LOCALE_USER_DEFAULT,
+                             TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
+                             &st, "hh':'mm':'ss", TimeBuf, 50);
+
+               snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf);
+       } else {
+               buf[0] = 0;
+       }
+}
diff --git a/lib/isc/win32/unistd.h b/lib/isc/win32/unistd.h
new file mode 100644 (file)
index 0000000..889f0b8
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2004, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000, 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: unistd.h,v 1.8 2008/01/23 03:22:43 tbox Exp $ */
+
+/* None of these are defined in NT, so define them for our use */
+#define O_NONBLOCK 1
+#define PORT_NONBLOCK O_NONBLOCK
+
+/*
+ * fcntl() commands
+ */
+#define F_SETFL 0
+#define F_GETFL 1
+#define F_SETFD 2
+#define F_GETFD 3
+/*
+ * Enough problems not having full fcntl() without worrying about this!
+ */
+#undef F_DUPFD
+
+int fcntl(int, int, ...);
+
+/*
+ * access() related definitions for winXP
+ */
+#include <io.h>
+
+#ifndef W_OK
+#define W_OK 2
+#endif
+
+#ifndef R_OK
+#define R_OK 4
+#endif
+
+#define access _access
+
+#include <process.h>
diff --git a/lib/isc/win32/version.c b/lib/isc/win32/version.c
new file mode 100644 (file)
index 0000000..6d5c1fd
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: version.c,v 1.7 2007/06/19 23:47:19 tbox Exp $ */
+
+#include <versions.h>
+
+#include <isc/version.h>
+
+LIBISC_EXTERNAL_DATA const char isc_version[] = VERSION;
+
+LIBISC_EXTERNAL_DATA const unsigned int isc_libinterface = LIBINTERFACE;
+LIBISC_EXTERNAL_DATA const unsigned int isc_librevision = LIBREVISION;
+LIBISC_EXTERNAL_DATA const unsigned int isc_libage = LIBAGE;
index 05ca09e354d2549b392e5a267f2c0dcf5bc942c2..56498d0ade10ed4c64e432bc1afdac347b2b5385 100644 (file)
@@ -1,21 +1,21 @@
 /*
- * Copyright (C) 2002 Internet Software Consortium.
+ * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2002  Internet Software Consortium.
  *
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: win32os.c,v 1.2 2002/08/03 01:36:24 mayer Exp $ */
+/* $Id: win32os.c,v 1.5 2007/06/19 23:47:19 tbox Exp $ */
 
 #include <windows.h>
 
diff --git a/lib/isc/x86_32/include/isc/atomic.h b/lib/isc/x86_32/include/isc/atomic.h
new file mode 100644 (file)
index 0000000..bf2148c
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.10 2008/01/24 23:47:00 tbox Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+/*
+ * This routine atomically increments the value stored in 'p' by 'val', and
+ * returns the previous value.
+ */
+static __inline__ isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+       isc_int32_t prev = val;
+
+       __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+               "lock;"
+#endif
+               "xadd %0, %1"
+               :"=q"(prev)
+               :"m"(*p), "0"(prev)
+               :"memory", "cc");
+
+       return (prev);
+}
+
+#ifdef ISC_PLATFORM_HAVEXADDQ
+static __inline__ isc_int64_t
+isc_atomic_xaddq(isc_int64_t *p, isc_int64_t val) {
+       isc_int64_t prev = val;
+
+       __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+           "lock;"
+#endif
+           "xaddq %0, %1"
+           :"=q"(prev)
+           :"m"(*p), "0"(prev)
+           :"memory", "cc");
+
+       return (prev);
+}
+#endif /* ISC_PLATFORM_HAVEXADDQ */
+
+/*
+ * This routine atomically stores the value 'val' in 'p'.
+ */
+static __inline__ void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+       __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+               /*
+                * xchg should automatically lock memory, but we add it
+                * explicitly just in case (it at least doesn't harm)
+                */
+               "lock;"
+#endif
+
+               "xchgl %1, %0"
+               :
+               : "r"(val), "m"(*p)
+               : "memory");
+}
+
+/*
+ * This routine atomically replaces the value in 'p' with 'val', if the
+ * original value is equal to 'cmpval'.  The original value is returned in any
+ * case.
+ */
+static __inline__ isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+       __asm__ volatile(
+#ifdef ISC_PLATFORM_USETHREADS
+               "lock;"
+#endif
+               "cmpxchgl %1, %2"
+               : "=a"(cmpval)
+               : "r"(val), "m"(*p), "a"(cmpval)
+               : "memory");
+
+       return (cmpval);
+}
+
+#elif defined(ISC_PLATFORM_USESTDASM)
+/*
+ * The followings are "generic" assembly code which implements the same
+ * functionality in case the gcc extension cannot be used.  It should be
+ * better to avoid inlining below, since we directly refer to specific
+ * positions of the stack frame, which would not actually point to the
+ * intended address in the embedded mnemonic.
+ */
+#include <isc/util.h>          /* for 'UNUSED' macro */
+
+static isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+       UNUSED(p);
+       UNUSED(val);
+
+       __asm (
+               "movl 8(%ebp), %ecx\n"
+               "movl 12(%ebp), %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+               "lock;"
+#endif
+               "xadd %edx, (%ecx)\n"
+
+               /*
+                * set the return value directly in the register so that we
+                * can avoid guessing the correct position in the stack for a
+                * local variable.
+                */
+               "movl %edx, %eax"
+               );
+}
+
+static void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+       UNUSED(p);
+       UNUSED(val);
+
+       __asm (
+               "movl 8(%ebp), %ecx\n"
+               "movl 12(%ebp), %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+               "lock;"
+#endif
+               "xchgl (%ecx), %edx\n"
+               );
+}
+
+static isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+       UNUSED(p);
+       UNUSED(cmpval);
+       UNUSED(val);
+
+       __asm (
+               "movl 8(%ebp), %ecx\n"
+               "movl 12(%ebp), %eax\n" /* must be %eax for cmpxchgl */
+               "movl 16(%ebp), %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+               "lock;"
+#endif
+
+               /*
+                * If (%ecx) == %eax then (%ecx) := %edx.
+                % %eax is set to old (%ecx), which will be the return value.
+                */
+               "cmpxchgl %edx, (%ecx)"
+               );
+}
+#else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */
+
+#error "unsupported compiler.  disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */
diff --git a/lib/isc/x86_64/include/isc/atomic.h b/lib/isc/x86_64/include/isc/atomic.h
new file mode 100644 (file)
index 0000000..f57bd2a
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: atomic.h,v 1.6 2008/01/24 23:47:00 tbox Exp $ */
+
+#ifndef ISC_ATOMIC_H
+#define ISC_ATOMIC_H 1
+
+#include <isc/platform.h>
+#include <isc/types.h>
+
+#ifdef ISC_PLATFORM_USEGCCASM
+
+/* We share the gcc-version with x86_32 */
+#error "impossible case.  check build configuration"
+
+#elif defined(ISC_PLATFORM_USESTDASM)
+/*
+ * The followings are "generic" assembly code which implements the same
+ * functionality in case the gcc extension cannot be used.  It should be
+ * better to avoid inlining below, since we directly refer to specific
+ * registers for arguments, which would not actually correspond to the
+ * intended address or value in the embedded mnemonic.
+ */
+#include <isc/util.h>          /* for 'UNUSED' macro */
+
+static isc_int32_t
+isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
+       UNUSED(p);
+       UNUSED(val);
+
+       __asm (
+               "movq %rdi, %rdx\n"
+               "movl %esi, %eax\n"
+#ifdef ISC_PLATFORM_USETHREADS
+               "lock;"
+#endif
+               "xadd %eax, (%rdx)\n"
+               /*
+                * XXX: assume %eax will be used as the return value.
+                */
+               );
+}
+
+#ifdef ISC_PLATFORM_HAVEXADDQ
+static isc_int64_t
+isc_atomic_xaddq(isc_int64_t *p, isc_int64_t val) {
+       UNUSED(p);
+       UNUSED(val);
+
+       __asm (
+               "movq %rdi, %rdx\n"
+               "movq %rsi, %rax\n"
+#ifdef ISC_PLATFORM_USETHREADS
+               "lock;"
+#endif
+               "xaddq %rax, (%rdx)\n"
+               /*
+                * XXX: assume %rax will be used as the return value.
+                */
+               );
+}
+#endif
+
+static void
+isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
+       UNUSED(p);
+       UNUSED(val);
+
+       __asm (
+               "movq %rdi, %rax\n"
+               "movl %esi, %edx\n"
+#ifdef ISC_PLATFORM_USETHREADS
+               "lock;"
+#endif
+               "xchgl (%rax), %edx\n"
+               /*
+                * XXX: assume %rax will be used as the return value.
+                */
+               );
+}
+
+static isc_int32_t
+isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
+       UNUSED(p);
+       UNUSED(cmpval);
+       UNUSED(val);
+
+       __asm (
+               "movl %edx, %ecx\n"
+               "movl %esi, %eax\n"
+               "movq %rdi, %rdx\n"
+
+#ifdef ISC_PLATFORM_USETHREADS
+               "lock;"
+#endif
+               /*
+                * If (%rdi) == %eax then (%rdi) := %edx.
+                * %eax is set to old (%ecx), which will be the return value.
+                */
+               "cmpxchgl %ecx, (%rdx)"
+               );
+}
+
+#else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */
+
+#error "unsupported compiler.  disable atomic ops by --disable-atomic"
+
+#endif
+#endif /* ISC_ATOMIC_H */