aboutsummaryrefslogtreecommitdiff
path: root/contrib/isc-dhcp/omapip
diff options
context:
space:
mode:
authorMurray Stokely <murray@FreeBSD.org>2002-02-19 11:04:34 +0000
committerMurray Stokely <murray@FreeBSD.org>2002-02-19 11:04:34 +0000
commitce99b771f886a2c842db7aa803c9a5a5918f42c8 (patch)
tree229464d9b3244ab78e2784c9a0a1f78de317089a /contrib/isc-dhcp/omapip
parent7657fb140fbd218ea326d55bd3c43c4077f03d9a (diff)
downloadsrc-ce99b771f886a2c842db7aa803c9a5a5918f42c8.tar.gz
src-ce99b771f886a2c842db7aa803c9a5a5918f42c8.zip
Import ISC DHCP 3.0.1 RC6 client.
Notes
Notes: svn path=/vendor/isc-dhcp/dist/; revision=90908
Diffstat (limited to 'contrib/isc-dhcp/omapip')
-rw-r--r--contrib/isc-dhcp/omapip/Makefile.dist106
-rw-r--r--contrib/isc-dhcp/omapip/alloc.c1151
-rw-r--r--contrib/isc-dhcp/omapip/array.c172
-rw-r--r--contrib/isc-dhcp/omapip/auth.c273
-rw-r--r--contrib/isc-dhcp/omapip/buffer.c718
-rw-r--r--contrib/isc-dhcp/omapip/connection.c1026
-rw-r--r--contrib/isc-dhcp/omapip/convert.c193
-rw-r--r--contrib/isc-dhcp/omapip/dispatch.c604
-rw-r--r--contrib/isc-dhcp/omapip/errwarn.c363
-rw-r--r--contrib/isc-dhcp/omapip/generic.c311
-rw-r--r--contrib/isc-dhcp/omapip/handle.c304
-rw-r--r--contrib/isc-dhcp/omapip/hash.c425
-rw-r--r--contrib/isc-dhcp/omapip/inet_addr.c150
-rw-r--r--contrib/isc-dhcp/omapip/listener.c477
-rw-r--r--contrib/isc-dhcp/omapip/message.c769
-rw-r--r--contrib/isc-dhcp/omapip/mrtrace.c488
-rw-r--r--contrib/isc-dhcp/omapip/omapi.3254
-rw-r--r--contrib/isc-dhcp/omapip/protocol.c1319
-rw-r--r--contrib/isc-dhcp/omapip/result.c125
-rw-r--r--contrib/isc-dhcp/omapip/support.c872
-rw-r--r--contrib/isc-dhcp/omapip/test.c108
-rw-r--r--contrib/isc-dhcp/omapip/toisc.c324
-rw-r--r--contrib/isc-dhcp/omapip/trace.c718
23 files changed, 11250 insertions, 0 deletions
diff --git a/contrib/isc-dhcp/omapip/Makefile.dist b/contrib/isc-dhcp/omapip/Makefile.dist
new file mode 100644
index 000000000000..099f83e10ff6
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/Makefile.dist
@@ -0,0 +1,106 @@
+# Makefile.dist
+#
+# Copyright (c) 1996-2001 Internet Software Consortium.
+# Use is subject to license terms which appear in the file named
+# ISC-LICENSE that should have accompanied this file when you
+# received it. If a file named ISC-LICENSE did not accompany this
+# file, or you are not sure the one you have is correct, you may
+# obtain an applicable copy of the license at:
+#
+# http://www.isc.org/isc-license-1.0.html.
+#
+# This file is part of the ISC DHCP distribution. The documentation
+# associated with this file is listed in the file DOCUMENTATION,
+# included in the top-level directory of this release.
+#
+# Support and other services are available for ISC products - see
+# http://www.isc.org for more information.
+#
+
+CATMANPAGES = omapi.cat3
+SEDMANPAGES = omapi.man3
+SRC = protocol.c buffer.c alloc.c result.c connection.c errwarn.c \
+ listener.c dispatch.c generic.c support.c handle.c message.c \
+ convert.c hash.c auth.c inet_addr.c array.c trace.c mrtrace.c \
+ toisc.c
+
+OBJ = protocol.o buffer.o alloc.o result.o connection.o errwarn.o \
+ listener.o dispatch.o generic.o support.o handle.o message.o \
+ convert.o hash.o auth.o inet_addr.o array.o trace.o mrtrace.o \
+ toisc.o
+
+MAN = omapi.3
+
+INCLUDES = $(BINDINC) -I$(TOP)/includes
+CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS)
+
+all: libomapi.a svtest $(CATMANPAGES)
+
+svtest: test.o libomapi.a $(BINDLIB) ../dst/libdst.a
+ $(CC) $(DEBUG) $(LFLAGS) -o svtest test.o $(BINDLIB) \
+ libomapi.a ../dst/libdst.a $(LIBS)
+
+libomapi.a: $(OBJ)
+ rm -f libomapi.a
+ ar cruv libomapi.a $(OBJ)
+ $(RANLIB) libomapi.a
+
+install: all
+ for dir in $(LIBDIR) $(LIBMANDIR) $(INCDIR)/omapip $(INCDIR)/isc-dhcp;\
+ do \
+ foo=""; \
+ for bar in `echo $(DESTDIR)$${dir} |tr / ' '`; do \
+ foo=$${foo}/$$bar; \
+ if [ ! -d $$foo ]; then \
+ mkdir $$foo; \
+ chmod 755 $$foo; \
+ fi; \
+ done; \
+ done
+ $(INSTALL) libomapi.a $(DESTDIR)$(LIBDIR)
+ $(CHMOD) 644 $(DESTDIR)$(LIBDIR)/libomapi.a
+ for file in alloc.h buffer.h omapip.h; do \
+ $(INSTALL) $(TOP)/includes/omapip/$$file \
+ $(DESTDIR)$(INCDIR)/omapip; \
+ $(CHMOD) 644 $(DESTDIR)$(INCDIR)/omapip/$$file; \
+ done
+ for file in boolean.h dst.h int.h lang.h list.h result.h types.h; do \
+ $(INSTALL) $(TOP)/includes/isc-dhcp/$$file \
+ $(DESTDIR)$(INCDIR)/isc-dhcp; \
+ $(CHMOD) 644 $(DESTDIR)$(INCDIR)/isc-dhcp/$$file; \
+ done
+ for man in $(MAN); do \
+ prefix=`echo $$man |sed -e 's/\.[0-9]$$//'`; \
+ suffix=`echo $$man |sed -e 's/.*\.\([0-9]\)$$/\1/'`; \
+ $(MANINSTALL) $(MANFROM) $${prefix}.$(MANCAT)$${suffix} $(MANTO) \
+ $(DESTDIR)$(LIBMANDIR)/$${prefix}$(LIBMANEXT); \
+ done
+
+depend:
+ $(MKDEP) $(INCLUDES) $(PREDEFINES) $(SRC)
+
+clean:
+ -rm -f $(OBJ) test.o svtest
+
+realclean: clean
+ -rm -f libomapi.a *~ $(CATMANPAGES) $(SEDMANPAGES)
+
+distclean: realclean
+ -rm -f Makefile
+
+links:
+ @for foo in $(SRC) $(MAN) test.c; do \
+ if [ ! -b $$foo ]; then \
+ rm -f $$foo; \
+ fi; \
+ ln -s $(TOP)/omapip/$$foo $$foo; \
+ done
+
+omapi.cat3: omapi.man3
+ nroff -man omapi.man3 >omapi.cat3
+
+omapi.man3: omapi.3
+ sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \
+ -e "s#RUNDIR#$(VARRUN)#g" < omapi.3 >omapi.man3
+
+# Dependencies (semi-automatically-generated)
diff --git a/contrib/isc-dhcp/omapip/alloc.c b/contrib/isc-dhcp/omapip/alloc.c
new file mode 100644
index 000000000000..245bdaf9becc
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/alloc.c
@@ -0,0 +1,1151 @@
+/* alloc.c
+
+ Functions supporting memory allocation for the object management
+ protocol... */
+
+/*
+ * Copyright (c) 1999-2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+struct dmalloc_preamble *dmalloc_list;
+unsigned long dmalloc_outstanding;
+unsigned long dmalloc_longterm;
+unsigned long dmalloc_generation;
+unsigned long dmalloc_cutoff_generation;
+#endif
+
+#if defined (DEBUG_RC_HISTORY)
+struct rc_history_entry rc_history [RC_HISTORY_MAX];
+int rc_history_index;
+int rc_history_count;
+#endif
+
+#if defined (DEBUG_RC_HISTORY)
+static void print_rc_hist_entry (int);
+#endif
+
+VOIDPTR dmalloc (size, file, line)
+ unsigned size;
+ const char *file;
+ int line;
+{
+ unsigned char *foo = malloc (size + DMDSIZE);
+ int i;
+ VOIDPTR *bar;
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ struct dmalloc_preamble *dp;
+#endif
+ if (!foo)
+ return (VOIDPTR)0;
+ bar = (VOIDPTR)(foo + DMDOFFSET);
+ memset (bar, 0, size);
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ dp = (struct dmalloc_preamble *)foo;
+ dp -> prev = dmalloc_list;
+ if (dmalloc_list)
+ dmalloc_list -> next = dp;
+ dmalloc_list = dp;
+ dp -> next = (struct dmalloc_preamble *)0;
+ dp -> size = size;
+ dp -> file = file;
+ dp -> line = line;
+ dp -> generation = dmalloc_generation++;
+ dmalloc_outstanding += size;
+ for (i = 0; i < DMLFSIZE; i++)
+ dp -> low_fence [i] =
+ (((unsigned long)
+ (&dp -> low_fence [i])) % 143) + 113;
+ for (i = DMDOFFSET; i < DMDSIZE; i++)
+ foo [i + size] =
+ (((unsigned long)
+ (&foo [i + size])) % 143) + 113;
+#if defined (DEBUG_MALLOC_POOL_EXHAUSTIVELY)
+ /* Check _every_ entry in the pool! Very expensive. */
+ for (dp = dmalloc_list; dp; dp = dp -> prev) {
+ for (i = 0; i < DMLFSIZE; i++) {
+ if (dp -> low_fence [i] !=
+ (((unsigned long)
+ (&dp -> low_fence [i])) % 143) + 113)
+ {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ foo = (unsigned char *)dp;
+ for (i = DMDOFFSET; i < DMDSIZE; i++) {
+ if (foo [i + dp -> size] !=
+ (((unsigned long)
+ (&foo [i + dp -> size])) % 143) + 113) {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ }
+#endif
+#endif
+#ifdef DEBUG_REFCNT_DMALLOC_FREE
+ rc_register (file, line, 0, foo + DMDOFFSET, 1, 0, RC_MALLOC);
+#endif
+ return bar;
+}
+
+void dfree (ptr, file, line)
+ VOIDPTR ptr;
+ const char *file;
+ int line;
+{
+ if (!ptr) {
+ log_error ("dfree %s(%d): free on null pointer.", file, line);
+ return;
+ }
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ {
+ unsigned char *bar = ptr;
+ struct dmalloc_preamble *dp, *cur;
+ int i;
+ bar -= DMDOFFSET;
+ cur = (struct dmalloc_preamble *)bar;
+ for (dp = dmalloc_list; dp; dp = dp -> prev)
+ if (dp == cur)
+ break;
+ if (!dp) {
+ log_error ("%s(%d): freeing unknown memory: %lx",
+ file, line, (unsigned long)cur);
+ abort ();
+ }
+ if (dp -> prev)
+ dp -> prev -> next = dp -> next;
+ if (dp -> next)
+ dp -> next -> prev = dp -> prev;
+ if (dp == dmalloc_list)
+ dmalloc_list = dp -> prev;
+ if (dp -> generation >= dmalloc_cutoff_generation)
+ dmalloc_outstanding -= dp -> size;
+ else
+ dmalloc_longterm -= dp -> size;
+
+ for (i = 0; i < DMLFSIZE; i++) {
+ if (dp -> low_fence [i] !=
+ (((unsigned long)
+ (&dp -> low_fence [i])) % 143) + 113)
+ {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ for (i = DMDOFFSET; i < DMDSIZE; i++) {
+ if (bar [i + dp -> size] !=
+ (((unsigned long)
+ (&bar [i + dp -> size])) % 143) + 113) {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ ptr = bar;
+ }
+#endif
+#ifdef DEBUG_REFCNT_DMALLOC_FREE
+ rc_register (file, line,
+ 0, (unsigned char *)ptr + DMDOFFSET, 0, 1, RC_MALLOC);
+#endif
+ free (ptr);
+}
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+/* For allocation functions that keep their own free lists, we want to
+ account for the reuse of the memory. */
+
+void dmalloc_reuse (foo, file, line, justref)
+ VOIDPTR foo;
+ const char *file;
+ int line;
+ int justref;
+{
+ struct dmalloc_preamble *dp;
+
+ /* Get the pointer to the dmalloc header. */
+ dp = foo;
+ dp--;
+
+ /* If we just allocated this and are now referencing it, this
+ function would almost be a no-op, except that it would
+ increment the generation count needlessly. So just return
+ in this case. */
+ if (dp -> generation == dmalloc_generation)
+ return;
+
+ /* If this is longterm data, and we just made reference to it,
+ don't put it on the short-term list or change its name -
+ we don't need to know about this. */
+ if (dp -> generation < dmalloc_cutoff_generation && justref)
+ return;
+
+ /* Take it out of the place in the allocated list where it was. */
+ if (dp -> prev)
+ dp -> prev -> next = dp -> next;
+ if (dp -> next)
+ dp -> next -> prev = dp -> prev;
+ if (dp == dmalloc_list)
+ dmalloc_list = dp -> prev;
+
+ /* Account for its removal. */
+ if (dp -> generation >= dmalloc_cutoff_generation)
+ dmalloc_outstanding -= dp -> size;
+ else
+ dmalloc_longterm -= dp -> size;
+
+ /* Now put it at the head of the list. */
+ dp -> prev = dmalloc_list;
+ if (dmalloc_list)
+ dmalloc_list -> next = dp;
+ dmalloc_list = dp;
+ dp -> next = (struct dmalloc_preamble *)0;
+
+ /* Change the reference location information. */
+ dp -> file = file;
+ dp -> line = line;
+
+ /* Increment the generation. */
+ dp -> generation = dmalloc_generation++;
+
+ /* Account for it. */
+ dmalloc_outstanding += dp -> size;
+}
+
+void dmalloc_dump_outstanding ()
+{
+ static unsigned long dmalloc_cutoff_point;
+ struct dmalloc_preamble *dp;
+ unsigned char *foo;
+ int i;
+
+ if (!dmalloc_cutoff_point)
+ dmalloc_cutoff_point = dmalloc_cutoff_generation;
+ for (dp = dmalloc_list; dp; dp = dp -> prev) {
+ if (dp -> generation <= dmalloc_cutoff_point)
+ break;
+#if defined (DEBUG_MALLOC_POOL)
+ for (i = 0; i < DMLFSIZE; i++) {
+ if (dp -> low_fence [i] !=
+ (((unsigned long)
+ (&dp -> low_fence [i])) % 143) + 113)
+ {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+ foo = (unsigned char *)dp;
+ for (i = DMDOFFSET; i < DMDSIZE; i++) {
+ if (foo [i + dp -> size] !=
+ (((unsigned long)
+ (&foo [i + dp -> size])) % 143) + 113) {
+ log_error ("malloc fence modified: %s(%d)",
+ dp -> file, dp -> line);
+ abort ();
+ }
+ }
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ /* Don't count data that's actually on a free list
+ somewhere. */
+ if (dp -> file) {
+#if defined (DEBUG_RC_HISTORY)
+ int i, count, inhistory = 0, noted = 0;
+
+ /* If we have the info, see if this is actually
+ new garbage. */
+ if (rc_history_count < RC_HISTORY_MAX) {
+ count = rc_history_count;
+ } else
+ count = RC_HISTORY_MAX;
+ i = rc_history_index - 1;
+ if (i < 0)
+ i += RC_HISTORY_MAX;
+
+ do {
+ if (rc_history [i].addr == dp + 1) {
+ inhistory = 1;
+ if (!noted) {
+ log_info (" %s(%d): %d", dp -> file,
+ dp -> line, dp -> size);
+ noted = 1;
+ }
+ print_rc_hist_entry (i);
+ if (!rc_history [i].refcnt)
+ break;
+ }
+ if (--i < 0)
+ i = RC_HISTORY_MAX - 1;
+ } while (count--);
+ if (!inhistory)
+#endif
+ log_info (" %s(%d): %d",
+ dp -> file, dp -> line, dp -> size);
+ }
+#endif
+ }
+ if (dmalloc_list)
+ dmalloc_cutoff_point = dmalloc_list -> generation;
+}
+#endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */
+
+#if defined (DEBUG_RC_HISTORY)
+static void print_rc_hist_entry (int i)
+{
+ log_info (" referenced by %s(%d)[%lx]: addr = %lx refcnt = %x",
+ rc_history [i].file, rc_history [i].line,
+ (unsigned long)rc_history [i].reference,
+ (unsigned long)rc_history [i].addr,
+ rc_history [i].refcnt);
+}
+
+void dump_rc_history (void *addr)
+{
+ int i;
+
+ i = rc_history_index;
+ if (!rc_history [i].file)
+ i = 0;
+ else if (rc_history_count < RC_HISTORY_MAX) {
+ i -= rc_history_count;
+ if (i < 0)
+ i += RC_HISTORY_MAX;
+ }
+ rc_history_count = 0;
+
+ while (rc_history [i].file) {
+ if (!addr || addr == rc_history [i].addr)
+ print_rc_hist_entry (i);
+ ++i;
+ if (i == RC_HISTORY_MAX)
+ i = 0;
+ if (i == rc_history_index)
+ break;
+ }
+}
+void rc_history_next (int d)
+{
+#if defined (RC_HISTORY_COMPRESSION)
+ int i, j = 0, m, n = 0;
+ void *ap, *rp;
+
+ /* If we are decreasing the reference count, try to find the
+ entry where the reference was made and eliminate it; then
+ we can also eliminate this reference. */
+ if (d) {
+ m = rc_history_index - 1000;
+ if (m < -1)
+ m = -1;
+ ap = rc_history [rc_history_index].addr;
+ rp = rc_history [rc_history_index].reference;
+ for (i = rc_history_index - 1; i > m; i--) {
+ if (rc_history [i].addr == ap) {
+ if (rc_history [i].reference == rp) {
+ if (n > 10) {
+ for (n = i; n <= rc_history_index; n++)
+ print_rc_hist_entry (n);
+ n = 11;
+ }
+ memmove (&rc_history [i],
+ &rc_history [i + 1],
+ (unsigned)((rc_history_index - i) *
+ sizeof (struct rc_history_entry)));
+ --rc_history_count;
+ --rc_history_index;
+ for (j = i; j < rc_history_count; j++) {
+ if (rc_history [j].addr == ap)
+ --rc_history [j].refcnt;
+ }
+ if (n > 10) {
+ for (n = i; n <= rc_history_index; n++)
+ print_rc_hist_entry (n);
+ n = 11;
+ exit (0);
+ }
+ return;
+ }
+ }
+ }
+ }
+#endif
+ if (++rc_history_index == RC_HISTORY_MAX)
+ rc_history_index = 0;
+ ++rc_history_count;
+}
+#endif
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+struct caller {
+ struct dmalloc_preamble *dp;
+ int count;
+};
+
+static int dmalloc_find_entry (struct dmalloc_preamble *dp,
+ struct caller *array,
+ int min, int max)
+{
+ int middle;
+ int cmp;
+
+ middle = (min + max) / 2;
+ if (middle == min)
+ return middle;
+ if (array [middle].dp -> file == dp -> file) {
+ if (array [middle].dp -> line == dp -> line)
+ return middle;
+ else if (array [middle].dp -> line < dp -> line)
+ return dmalloc_find_entry (dp, array, middle, max);
+ else
+ return dmalloc_find_entry (dp, array, 0, middle);
+ } else if (array [middle].dp -> file < dp -> file)
+ return dmalloc_find_entry (dp, array, middle, max);
+ else
+ return dmalloc_find_entry (dp, array, 0, middle);
+}
+
+void omapi_print_dmalloc_usage_by_caller ()
+{
+ struct dmalloc_preamble *dp;
+ unsigned char *foo;
+ int ccur, cmax, i, j;
+ struct caller cp [1024];
+
+ cmax = 1024;
+ ccur = 0;
+
+ memset (cp, 0, sizeof cp);
+ for (dp = dmalloc_list; dp; dp = dp -> prev) {
+ i = dmalloc_find_entry (dp, cp, 0, ccur);
+ if ((i == ccur ||
+ cp [i].dp -> file != dp -> file ||
+ cp [i].dp -> line != dp -> line) &&
+ ccur == cmax) {
+ log_error ("no space for memory usage summary.");
+ return;
+ }
+ if (i == ccur) {
+ cp [ccur++].dp = dp;
+ cp [i].count = 1;
+ } else if (cp [i].dp -> file < dp -> file ||
+ (cp [i].dp -> file == dp -> file &&
+ cp [i].dp -> line < dp -> line)) {
+ if (i + 1 != ccur)
+ memmove (cp + i + 2, cp + i + 1,
+ (ccur - i) * sizeof *cp);
+ cp [i + 1].dp = dp;
+ cp [i + 1].count = 1;
+ ccur++;
+ } else if (cp [i].dp -> file != dp -> file ||
+ cp [i].dp -> line != dp -> line) {
+ memmove (cp + i + 1,
+ cp + i, (ccur - i) * sizeof *cp);
+ cp [i].dp = dp;
+ cp [i].count = 1;
+ ccur++;
+ } else
+ cp [i].count++;
+#if 0
+ printf ("%d\t%s:%d\n", i, dp -> file, dp -> line);
+ dump_rc_history (dp + 1);
+#endif
+ }
+ for (i = 0; i < ccur; i++) {
+ printf ("%d\t%s:%d\t%d\n", i,
+ cp [i].dp -> file, cp [i].dp -> line, cp [i].count);
+ dump_rc_history (cp [i].dp + 1);
+ }
+}
+#endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */
+
+isc_result_t omapi_object_allocate (omapi_object_t **o,
+ omapi_object_type_t *type,
+ size_t size,
+ const char *file, int line)
+{
+ size_t tsize;
+ omapi_object_t *foo;
+ isc_result_t status;
+
+ if (type -> allocator) {
+ foo = (omapi_object_t *)0;
+ status = (*type -> allocator) (&foo, file, line);
+ tsize = type -> size;
+ } else
+ status = ISC_R_NOMEMORY;
+ if (status == ISC_R_NOMEMORY) {
+ if (type -> sizer)
+ tsize = (*type -> sizer) (size);
+ else
+ tsize = type -> size;
+
+ /* Sanity check. */
+ if (tsize < sizeof (omapi_object_t))
+ return ISC_R_INVALIDARG;
+
+ foo = dmalloc (tsize, file, line);
+ if (!foo)
+ return ISC_R_NOMEMORY;
+ }
+
+ status = omapi_object_initialize (foo, type, size, tsize, file, line);
+ if (status != ISC_R_SUCCESS) {
+ if (type -> freer)
+ (*type -> freer) (foo, file, line);
+ else
+ dfree (foo, file, line);
+ return status;
+ }
+ return omapi_object_reference (o, foo, file, line);
+}
+
+isc_result_t omapi_object_initialize (omapi_object_t *o,
+ omapi_object_type_t *type,
+ size_t usize, size_t psize,
+ const char *file, int line)
+{
+ memset (o, 0, psize);
+ o -> type = type;
+ if (type -> initialize)
+ (*type -> initialize) (o, file, line);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_object_reference (omapi_object_t **r,
+ omapi_object_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!",
+ file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, h -> type -> rc_flag);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_object_dereference (omapi_object_t **h,
+ const char *file, int line)
+{
+ int outer_reference = 0;
+ int inner_reference = 0;
+ int handle_reference = 0;
+ int extra_references;
+ omapi_object_t *p, *hp;
+
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ /* See if this object's inner object refers to it, but don't
+ count this as a reference if we're being asked to free the
+ reference from the inner object. */
+ if ((*h) -> inner && (*h) -> inner -> outer &&
+ h != &((*h) -> inner -> outer))
+ inner_reference = 1;
+
+ /* Ditto for the outer object. */
+ if ((*h) -> outer && (*h) -> outer -> inner &&
+ h != &((*h) -> outer -> inner))
+ outer_reference = 1;
+
+ /* Ditto for the outer object. The code below assumes that
+ the only reason we'd get a dereference from the handle
+ table is if this function does it - otherwise we'd have to
+ traverse the handle table to find the address where the
+ reference is stored and compare against that, and we don't
+ want to do that if we can avoid it. */
+ if ((*h) -> handle)
+ handle_reference = 1;
+
+ /* If we are getting rid of the last reference other than
+ references to inner and outer objects, or from the handle
+ table, then we must examine all the objects in either
+ direction to see if they hold any non-inner, non-outer,
+ non-handle-table references. If not, we need to free the
+ entire chain of objects. */
+ if ((*h) -> refcnt ==
+ inner_reference + outer_reference + handle_reference + 1) {
+ if (inner_reference || outer_reference || handle_reference) {
+ /* XXX we could check for a reference from the
+ handle table here. */
+ extra_references = 0;
+ for (p = (*h) -> inner;
+ p && !extra_references; p = p -> inner) {
+ extra_references += p -> refcnt;
+ if (p -> inner && p -> inner -> outer == p)
+ --extra_references;
+ if (p -> outer)
+ --extra_references;
+ if (p -> handle)
+ --extra_references;
+ }
+ for (p = (*h) -> outer;
+ p && !extra_references; p = p -> outer) {
+ extra_references += p -> refcnt;
+ if (p -> outer && p -> outer -> inner == p)
+ --extra_references;
+ if (p -> inner)
+ --extra_references;
+ if (p -> handle)
+ --extra_references;
+ }
+ } else
+ extra_references = 0;
+
+ if (!extra_references) {
+ hp = *h;
+ *h = 0;
+ hp -> refcnt--;
+ if (inner_reference)
+ omapi_object_dereference
+ (&hp -> inner, file, line);
+ if (outer_reference)
+ omapi_object_dereference
+ (&hp -> outer, file, line);
+/* if (!hp -> type -> freer) */
+ rc_register (file, line, h, hp,
+ 0, 1, hp -> type -> rc_flag);
+ if (hp -> type -> destroy)
+ (*(hp -> type -> destroy)) (hp, file, line);
+ if (hp -> type -> freer)
+ (hp -> type -> freer (hp, file, line));
+ else
+ dfree (hp, file, line);
+ } else {
+ (*h) -> refcnt--;
+/* if (!(*h) -> type -> freer) */
+ rc_register (file, line,
+ h, *h, (*h) -> refcnt, 1,
+ (*h) -> type -> rc_flag);
+ }
+ } else {
+ (*h) -> refcnt--;
+/* if (!(*h) -> type -> freer) */
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1,
+ (*h) -> type -> rc_flag);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_buffer_new (omapi_buffer_t **h,
+ const char *file, int line)
+{
+ omapi_buffer_t *t;
+ isc_result_t status;
+
+ t = (omapi_buffer_t *)dmalloc (sizeof *t, file, line);
+ if (!t)
+ return ISC_R_NOMEMORY;
+ memset (t, 0, sizeof *t);
+ status = omapi_buffer_reference (h, t, file, line);
+ if (status != ISC_R_SUCCESS)
+ dfree (t, file, line);
+ (*h) -> head = sizeof ((*h) -> buf) - 1;
+ return status;
+}
+
+isc_result_t omapi_buffer_reference (omapi_buffer_t **r,
+ omapi_buffer_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!",
+ file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_buffer_dereference (omapi_buffer_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ --(*h) -> refcnt;
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt == 0)
+ dfree (*h, file, line);
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_typed_data_new (const char *file, int line,
+ omapi_typed_data_t **t,
+ omapi_datatype_t type, ...)
+{
+ va_list l;
+ omapi_typed_data_t *new;
+ unsigned len;
+ unsigned val;
+ int intval;
+ char *s;
+ isc_result_t status;
+ omapi_object_t *obj;
+
+ va_start (l, type);
+
+ switch (type) {
+ case omapi_datatype_int:
+ len = OMAPI_TYPED_DATA_INT_LEN;
+ intval = va_arg (l, int);
+ break;
+ case omapi_datatype_string:
+ s = va_arg (l, char *);
+ val = strlen (s);
+ len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val;
+ break;
+ case omapi_datatype_data:
+ val = va_arg (l, unsigned);
+ len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val;
+ break;
+ case omapi_datatype_object:
+ len = OMAPI_TYPED_DATA_OBJECT_LEN;
+ obj = va_arg (l, omapi_object_t *);
+ break;
+ default:
+ return ISC_R_INVALIDARG;
+ }
+
+ new = dmalloc (len, file, line);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, len);
+
+ switch (type) {
+ case omapi_datatype_int:
+ new -> u.integer = intval;
+ break;
+ case omapi_datatype_string:
+ memcpy (new -> u.buffer.value, s, val);
+ new -> u.buffer.len = val;
+ break;
+ case omapi_datatype_data:
+ new -> u.buffer.len = val;
+ break;
+ case omapi_datatype_object:
+ status = omapi_object_reference (&new -> u.object, obj,
+ file, line);
+ if (status != ISC_R_SUCCESS) {
+ dfree (new, file, line);
+ return status;
+ }
+ break;
+ }
+ new -> type = type;
+
+ return omapi_typed_data_reference (t, new, file, line);
+}
+
+isc_result_t omapi_typed_data_reference (omapi_typed_data_t **r,
+ omapi_typed_data_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!", file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_typed_data_dereference (omapi_typed_data_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ --((*h) -> refcnt);
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt <= 0 ) {
+ switch ((*h) -> type) {
+ case omapi_datatype_int:
+ case omapi_datatype_string:
+ case omapi_datatype_data:
+ default:
+ break;
+ case omapi_datatype_object:
+ omapi_object_dereference (&(*h) -> u.object,
+ file, line);
+ break;
+ }
+ dfree (*h, file, line);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_data_string_new (omapi_data_string_t **d, unsigned len,
+ const char *file, int line)
+{
+ omapi_data_string_t *new;
+
+ new = dmalloc (OMAPI_DATA_STRING_EMPTY_SIZE + len, file, line);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, OMAPI_DATA_STRING_EMPTY_SIZE);
+ new -> len = len;
+ return omapi_data_string_reference (d, new, file, line);
+}
+
+isc_result_t omapi_data_string_reference (omapi_data_string_t **r,
+ omapi_data_string_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!", file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_data_string_dereference (omapi_data_string_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ --((*h) -> refcnt);
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt <= 0 ) {
+ dfree (*h, file, line);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_value_new (omapi_value_t **d,
+ const char *file, int line)
+{
+ omapi_value_t *new;
+
+ new = dmalloc (sizeof *new, file, line);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, sizeof *new);
+ return omapi_value_reference (d, new, file, line);
+}
+
+isc_result_t omapi_value_reference (omapi_value_t **r,
+ omapi_value_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!",
+ file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_value_dereference (omapi_value_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with refcnt of zero!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ --((*h) -> refcnt);
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt == 0) {
+ if ((*h) -> name)
+ omapi_data_string_dereference (&(*h) -> name,
+ file, line);
+ if ((*h) -> value)
+ omapi_typed_data_dereference (&(*h) -> value,
+ file, line);
+ dfree (*h, file, line);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_addr_list_new (omapi_addr_list_t **d, unsigned count,
+ const char *file, int line)
+{
+ omapi_addr_list_t *new;
+
+ new = dmalloc ((count * sizeof (omapi_addr_t)) +
+ sizeof (omapi_addr_list_t), file, line);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, ((count * sizeof (omapi_addr_t)) +
+ sizeof (omapi_addr_list_t)));
+ new -> count = count;
+ new -> addresses = (omapi_addr_t *)(new + 1);
+ return omapi_addr_list_reference (d, new, file, line);
+}
+
+isc_result_t omapi_addr_list_reference (omapi_addr_list_t **r,
+ omapi_addr_list_t *h,
+ const char *file, int line)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): reference store into non-null pointer!",
+ file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_addr_list_dereference (omapi_addr_list_t **h,
+ const char *file, int line)
+{
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of null pointer!", file, line);
+ abort ();
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (POINTER_DEBUG)
+ log_error ("%s(%d): dereference of pointer with zero refcnt!",
+ file, line);
+#if defined (DEBUG_RC_HISTORY)
+ dump_rc_history (*h);
+#endif
+ abort ();
+#else
+ *h = 0;
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ --((*h) -> refcnt);
+ rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC);
+ if ((*h) -> refcnt <= 0 ) {
+ dfree (*h, file, line);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
diff --git a/contrib/isc-dhcp/omapip/array.c b/contrib/isc-dhcp/omapip/array.c
new file mode 100644
index 000000000000..56d8d9f25b05
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/array.c
@@ -0,0 +1,172 @@
+/* listener.c
+
+ Subroutines that support the omapi extensible array type. */
+
+/*
+ * Copyright (c) 2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+/* Allocate a new extensible array. */
+
+isc_result_t omapi_array_allocate (omapi_array_t **array,
+ omapi_array_ref_t ref,
+ omapi_array_deref_t deref,
+ const char *file, int line)
+{
+ isc_result_t status;
+ omapi_array_t *aptr;
+
+ if (!array || *array)
+ return ISC_R_INVALIDARG;
+ aptr = dmalloc (sizeof (omapi_array_t),file, line);
+ if (!aptr)
+ return ISC_R_NOMEMORY;
+ *array = aptr;
+ aptr -> ref = ref;
+ aptr -> deref = deref;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_array_free (omapi_array_t **array,
+ const char *file, int line)
+{
+ isc_result_t status;
+ omapi_array_t *aptr;
+ int i;
+
+ if (!array || !*array)
+ return ISC_R_INVALIDARG;
+ aptr = *array;
+ for (i = 0; i < aptr -> count; i++)
+ if (aptr -> data [i] && aptr -> deref)
+ (*aptr -> deref) (&aptr -> data [i], file, line);
+ dfree (aptr -> data, MDL);
+ dfree (aptr, MDL);
+ *array = (omapi_array_t *)0;
+ return ISC_R_SUCCESS;
+}
+
+/* Extend the size of the array by one entry (we may allocate more than that)
+ and store the specified value in the new array element. */
+
+isc_result_t omapi_array_extend (omapi_array_t *array, char *ptr,
+ int *index, const char *file, int line)
+{
+ isc_result_t status;
+ int new = array -> count;
+ status = omapi_array_set (array, ptr, new, file, line);
+ if (index && status == ISC_R_SUCCESS)
+ *index = new;
+ return status;
+}
+
+/* Set a value in the specified array, extending it if necessary. */
+
+isc_result_t omapi_array_set (omapi_array_t *array, void *ptr, int index,
+ const char *file, int line)
+{
+ char **newbuf;
+ int delta;
+ isc_result_t status;
+
+ if (!array)
+ return ISC_R_INVALIDARG;
+ if (!ptr)
+ return ISC_R_INVALIDARG;
+ if (index < 0)
+ return ISC_R_INVALIDARG;
+
+ /* If the proposed index is larger than the current available
+ space in the array, make more space in the array. */
+ if (array -> max <= index) {
+ delta = index - array -> max + 10;
+ newbuf = dmalloc ((array -> max + delta) * sizeof (char *),
+ file, line);
+ if (!newbuf)
+ return ISC_R_NOMEMORY;
+ /* Zero the new elements. */
+ memset (&newbuf [array -> max], 0, (sizeof (char *)) * delta);
+ array -> max += delta;
+ /* Copy the old array data into the new buffer. */
+ if (array -> data) {
+ memcpy (newbuf,
+ array -> data, array -> count * sizeof (char *));
+ dfree (array -> data, file, line);
+ }
+ array -> data = newbuf;
+ } else {
+ /* If there's already data there, and this is an array
+ of references, dereference what's there. */
+ if (array -> data [index]) {
+ status = ((*array -> deref) (&array -> data [index],
+ file, line));
+
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ }
+
+ /* Store the pointer using the referencer function. We have
+ either just memset this to zero or dereferenced what was
+ there previously, so there is no need to do anything if the
+ pointer we have been asked to store is null. */
+ if (ptr) {
+ status = (*array -> ref) (&array -> data [index], ptr,
+ file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ if (index >= array -> count)
+ array -> count = index + 1;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_array_lookup (char **ptr, omapi_array_t *array, int index,
+ const char *file, int line)
+{
+ if (!array || !ptr || *ptr || index < 0 || index >= array -> count)
+ return ISC_R_INVALIDARG;
+ if (array -> data [index])
+ return (*array -> ref) (ptr,
+ array -> data [index], file, line);
+ return ISC_R_NOTFOUND;
+}
+
+OMAPI_ARRAY_TYPE_DECL(omapi_object, omapi_object_t);
diff --git a/contrib/isc-dhcp/omapip/auth.c b/contrib/isc-dhcp/omapip/auth.c
new file mode 100644
index 000000000000..ea0c2f6b1092
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/auth.c
@@ -0,0 +1,273 @@
+/* auth.c
+
+ Subroutines having to do with authentication. */
+
+/*
+ * Copyright (c) 1998-2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#ifndef lint
+static char ocopyright[] =
+"$Id: auth.c,v 1.3.2.3 2001/10/17 03:27:56 mellon Exp $ Copyright 1998-2000 The Internet Software Consortium.";
+#endif
+
+#include <omapip/omapip_p.h>
+
+OMAPI_OBJECT_ALLOC (omapi_auth_key, omapi_auth_key_t, omapi_type_auth_key)
+typedef struct hash omapi_auth_hash_t;
+HASH_FUNCTIONS_DECL (omapi_auth_key, const char *,
+ omapi_auth_key_t, omapi_auth_hash_t)
+omapi_auth_hash_t *auth_key_hash;
+HASH_FUNCTIONS (omapi_auth_key, const char *, omapi_auth_key_t,
+ omapi_auth_hash_t,
+ omapi_auth_key_reference, omapi_auth_key_dereference)
+
+isc_result_t omapi_auth_key_new (omapi_auth_key_t **o, const char *file,
+ int line)
+{
+ return omapi_auth_key_allocate (o, file, line);
+}
+
+isc_result_t omapi_auth_key_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_auth_key_t *a;
+
+ if (h -> type != omapi_type_auth_key)
+ return ISC_R_INVALIDARG;
+ a = (omapi_auth_key_t *)h;
+
+ if (auth_key_hash)
+ omapi_auth_key_hash_delete (auth_key_hash, a -> name, 0, MDL);
+
+ if (a -> name)
+ dfree (a -> name, MDL);
+ if (a -> algorithm)
+ dfree (a -> algorithm, MDL);
+ if (a -> key)
+ omapi_data_string_dereference (&a -> key, MDL);
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_auth_key_enter (omapi_auth_key_t *a)
+{
+ omapi_auth_key_t *tk;
+
+ if (a -> type != omapi_type_auth_key)
+ return ISC_R_INVALIDARG;
+
+ tk = (omapi_auth_key_t *)0;
+ if (auth_key_hash) {
+ omapi_auth_key_hash_lookup (&tk, auth_key_hash,
+ a -> name, 0, MDL);
+ if (tk == a) {
+ omapi_auth_key_dereference (&tk, MDL);
+ return ISC_R_SUCCESS;
+ }
+ if (tk) {
+ omapi_auth_key_hash_delete (auth_key_hash,
+ tk -> name, 0, MDL);
+ omapi_auth_key_dereference (&tk, MDL);
+ }
+ } else {
+ if (!omapi_auth_key_new_hash (&auth_key_hash, 1, MDL))
+ return ISC_R_NOMEMORY;
+ }
+ omapi_auth_key_hash_add (auth_key_hash, a -> name, 0, a, MDL);
+ return ISC_R_SUCCESS;
+
+}
+
+isc_result_t omapi_auth_key_lookup_name (omapi_auth_key_t **a,
+ const char *name)
+{
+ if (!auth_key_hash)
+ return ISC_R_NOTFOUND;
+ if (!omapi_auth_key_hash_lookup (a, auth_key_hash, name, 0, MDL))
+ return ISC_R_NOTFOUND;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_auth_key_lookup (omapi_object_t **h,
+ omapi_object_t *id,
+ omapi_object_t *ref)
+{
+ isc_result_t status;
+ omapi_value_t *name = (omapi_value_t *)0;
+ omapi_value_t *algorithm = (omapi_value_t *)0;
+
+ if (!auth_key_hash)
+ return ISC_R_NOTFOUND;
+
+ if (!ref)
+ return ISC_R_NOKEYS;
+
+ status = omapi_get_value_str (ref, id, "name", &name);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ if ((name -> value -> type != omapi_datatype_string) &&
+ (name -> value -> type != omapi_datatype_data)) {
+ omapi_value_dereference (&name, MDL);
+ return ISC_R_NOTFOUND;
+ }
+
+ status = omapi_get_value_str (ref, id, "algorithm", &algorithm);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (&name, MDL);
+ return status;
+ }
+
+ if ((algorithm -> value -> type != omapi_datatype_string) &&
+ (algorithm -> value -> type != omapi_datatype_data)) {
+ omapi_value_dereference (&name, MDL);
+ omapi_value_dereference (&algorithm, MDL);
+ return ISC_R_NOTFOUND;
+ }
+
+
+ if (!omapi_auth_key_hash_lookup ((omapi_auth_key_t **)h, auth_key_hash,
+ (const char *)
+ name -> value -> u.buffer.value,
+ name -> value -> u.buffer.len, MDL)) {
+ omapi_value_dereference (&name, MDL);
+ omapi_value_dereference (&algorithm, MDL);
+ return ISC_R_NOTFOUND;
+ }
+
+ if (omapi_td_strcasecmp (algorithm -> value,
+ ((omapi_auth_key_t *)*h) -> algorithm) != 0) {
+ omapi_value_dereference (&name, MDL);
+ omapi_value_dereference (&algorithm, MDL);
+ omapi_object_dereference (h, MDL);
+ return ISC_R_NOTFOUND;
+ }
+
+ omapi_value_dereference (&name, MDL);
+ omapi_value_dereference (&algorithm, MDL);
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_auth_key_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *h)
+{
+ omapi_auth_key_t *a;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_auth_key)
+ return ISC_R_INVALIDARG;
+ a = (omapi_auth_key_t *)h;
+
+ /* Write only the name and algorithm -- not the secret! */
+ if (a -> name) {
+ status = omapi_connection_put_name (c, "name");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_string (c, a -> name);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ if (a -> algorithm) {
+ status = omapi_connection_put_name (c, "algorithm");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_string (c, a -> algorithm);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_auth_key_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_auth_key_t *a;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_auth_key)
+ return ISC_R_UNEXPECTED;
+ a = (omapi_auth_key_t *)h;
+
+ if (omapi_ds_strcmp (name, "name") == 0) {
+ if (a -> name)
+ return omapi_make_string_value
+ (value, name, a -> name, MDL);
+ else
+ return ISC_R_NOTFOUND;
+ } else if (omapi_ds_strcmp (name, "key") == 0) {
+ if (a -> key) {
+ status = omapi_value_new (value, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference
+ (&(*value) -> name, name, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (value, MDL);
+ return status;
+ }
+
+ status = omapi_typed_data_new (MDL, &(*value) -> value,
+ omapi_datatype_data,
+ a -> key -> len);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (value, MDL);
+ return status;
+ }
+
+ memcpy ((*value) -> value -> u.buffer.value,
+ a -> key -> value, a -> key -> len);
+ return ISC_R_SUCCESS;
+ } else
+ return ISC_R_NOTFOUND;
+ } else if (omapi_ds_strcmp (name, "algorithm") == 0) {
+ if (a -> algorithm)
+ return omapi_make_string_value
+ (value, name, a -> algorithm, MDL);
+ else
+ return ISC_R_NOTFOUND;
+ }
+
+ return ISC_R_SUCCESS;
+}
diff --git a/contrib/isc-dhcp/omapip/buffer.c b/contrib/isc-dhcp/omapip/buffer.c
new file mode 100644
index 000000000000..3d01357f9011
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/buffer.c
@@ -0,0 +1,718 @@
+/* buffer.c
+
+ Buffer access functions for the object management protocol... */
+
+/*
+ * Copyright (c) 1999-2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+#if defined (TRACING)
+static void trace_connection_input_input (trace_type_t *, unsigned, char *);
+static void trace_connection_input_stop (trace_type_t *);
+static void trace_connection_output_input (trace_type_t *, unsigned, char *);
+static void trace_connection_output_stop (trace_type_t *);
+static trace_type_t *trace_connection_input;
+static trace_type_t *trace_connection_output;
+static isc_result_t omapi_connection_reader_trace (omapi_object_t *,
+ unsigned, char *,
+ unsigned *);
+extern omapi_array_t *omapi_connections;
+
+void omapi_buffer_trace_setup ()
+{
+ trace_connection_input =
+ trace_type_register ("connection-input",
+ (void *)0,
+ trace_connection_input_input,
+ trace_connection_input_stop, MDL);
+ trace_connection_output =
+ trace_type_register ("connection-output",
+ (void *)0,
+ trace_connection_output_input,
+ trace_connection_output_stop, MDL);
+}
+
+static void trace_connection_input_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ unsigned left, taken, cc = 0;
+ char *s;
+ int32_t connect_index;
+ isc_result_t status;
+ omapi_connection_object_t *c = (omapi_connection_object_t *)0;
+
+ memcpy (&connect_index, buf, sizeof connect_index);
+ connect_index = ntohl (connect_index);
+
+ omapi_array_foreach_begin (omapi_connections,
+ omapi_connection_object_t, lp) {
+ if (lp -> index == ntohl (connect_index)) {
+ omapi_connection_reference (&c, lp, MDL);
+ omapi_connection_dereference (&lp, MDL);
+ break;
+ }
+ } omapi_array_foreach_end (omapi_connections,
+ omapi_connection_object_t, lp);
+
+ if (!c) {
+ log_error ("trace connection input: no connection index %ld",
+ (long int)connect_index);
+ return;
+ }
+
+ s = buf + sizeof connect_index;
+ left = length - sizeof connect_index;
+
+ while (left) {
+ taken = 0;
+ status = omapi_connection_reader_trace ((omapi_object_t *)c,
+ left, s, &taken);
+ if (status != ISC_R_SUCCESS) {
+ log_error ("trace connection input: %s",
+ isc_result_totext (status));
+ break;
+ }
+ if (!taken) {
+ if (cc > 0) {
+ log_error ("trace connection_input: %s",
+ "input is not being consumed.");
+ break;
+ }
+ cc++;
+ } else {
+ cc = 0;
+ left -= taken;
+ }
+ }
+ omapi_connection_dereference (&c, MDL);
+}
+
+static void trace_connection_input_stop (trace_type_t *ttype) { }
+
+static void trace_connection_output_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ /* We *could* check to see if the output is correct, but for now
+ we aren't going to do that. */
+}
+
+static void trace_connection_output_stop (trace_type_t *ttype) { }
+
+#endif
+
+/* Make sure that at least len bytes are in the input buffer, and if not,
+ read enough bytes to make up the difference. */
+
+isc_result_t omapi_connection_reader (omapi_object_t *h)
+{
+#if defined (TRACING)
+ return omapi_connection_reader_trace (h, 0, (char *)0, (unsigned *)0);
+}
+
+static isc_result_t omapi_connection_reader_trace (omapi_object_t *h,
+ unsigned stuff_len,
+ char *stuff_buf,
+ unsigned *stuff_taken)
+{
+#endif
+ omapi_buffer_t *buffer;
+ isc_result_t status;
+ unsigned read_len;
+ int read_status;
+ omapi_connection_object_t *c;
+ unsigned bytes_to_read;
+
+ if (!h || h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ /* Make sure c -> bytes_needed is valid. */
+ if (c -> bytes_needed < 0)
+ return ISC_R_INVALIDARG;
+
+ /* See if there are enough bytes. */
+ if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
+ c -> in_bytes > c -> bytes_needed)
+ return ISC_R_SUCCESS;
+
+
+ if (c -> inbufs) {
+ for (buffer = c -> inbufs; buffer -> next;
+ buffer = buffer -> next)
+ ;
+ if (!BUFFER_BYTES_FREE (buffer)) {
+ status = omapi_buffer_new (&buffer -> next, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ buffer = buffer -> next;
+ }
+ } else {
+ status = omapi_buffer_new (&c -> inbufs, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ buffer = c -> inbufs;
+ }
+
+ bytes_to_read = BUFFER_BYTES_FREE (buffer);
+
+ while (bytes_to_read) {
+ if (buffer -> tail > buffer -> head)
+ read_len = sizeof (buffer -> buf) - buffer -> tail;
+ else
+ read_len = buffer -> head - buffer -> tail;
+
+#if defined (TRACING)
+ if (trace_playback()) {
+ if (stuff_len) {
+ if (read_len > stuff_len)
+ read_len = stuff_len;
+ if (stuff_taken)
+ *stuff_taken += read_len;
+ memcpy (&buffer -> buf [buffer -> tail],
+ stuff_buf, read_len);
+ stuff_len -= read_len;
+ stuff_buf += read_len;
+ read_status = read_len;
+ } else {
+ break;
+ }
+ } else
+#endif
+ {
+ read_status = read (c -> socket,
+ &buffer -> buf [buffer -> tail],
+ read_len);
+ }
+ if (read_status < 0) {
+ if (errno == EWOULDBLOCK)
+ break;
+ else if (errno == EIO)
+ return ISC_R_IOERROR;
+ else if (errno == EINVAL)
+ return ISC_R_INVALIDARG;
+ else if (errno == ECONNRESET) {
+ omapi_disconnect (h, 1);
+ return ISC_R_SHUTTINGDOWN;
+ } else
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* If we got a zero-length read, as opposed to EWOULDBLOCK,
+ the remote end closed the connection. */
+ if (read_status == 0) {
+ omapi_disconnect (h, 0);
+ return ISC_R_SHUTTINGDOWN;
+ }
+#if defined (TRACING)
+ if (trace_record ()) {
+ trace_iov_t iov [2];
+ int32_t connect_index;
+
+ connect_index = htonl (c -> index);
+
+ iov [0].buf = (char *)&connect_index;
+ iov [0].len = sizeof connect_index;
+ iov [1].buf = &buffer -> buf [buffer -> tail];
+ iov [1].len = read_status;
+
+ status = (trace_write_packet_iov
+ (trace_connection_input, 2, iov, MDL));
+ if (status != ISC_R_SUCCESS) {
+ trace_stop ();
+ log_error ("trace connection input: %s",
+ isc_result_totext (status));
+ }
+ }
+#endif
+ buffer -> tail += read_status;
+ c -> in_bytes += read_status;
+ if (buffer -> tail == sizeof buffer -> buf)
+ buffer -> tail = 0;
+ if (read_status < read_len)
+ break;
+ bytes_to_read -= read_status;
+ }
+
+ if (c -> bytes_needed <= c -> in_bytes) {
+ omapi_signal (h, "ready", c);
+ }
+ return ISC_R_SUCCESS;
+}
+
+/* Put some bytes into the output buffer for a connection. */
+
+isc_result_t omapi_connection_copyin (omapi_object_t *h,
+ const unsigned char *bufp,
+ unsigned len)
+{
+ omapi_buffer_t *buffer;
+ isc_result_t status;
+ int bytes_copied = 0;
+ unsigned copy_len;
+ int sig_flags = SIG_MODE_UPDATE;
+ omapi_connection_object_t *c;
+
+ /* Make sure len is valid. */
+ if (len < 0)
+ return ISC_R_INVALIDARG;
+ if (!h || h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ /* If the connection is closed, return an error if the caller
+ tries to copy in. */
+ if (c -> state == omapi_connection_disconnecting ||
+ c -> state == omapi_connection_closed)
+ return ISC_R_NOTCONNECTED;
+
+ if (c -> outbufs) {
+ for (buffer = c -> outbufs;
+ buffer -> next; buffer = buffer -> next)
+ ;
+ } else {
+ status = omapi_buffer_new (&c -> outbufs, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ buffer = c -> outbufs;
+ }
+
+ while (bytes_copied < len) {
+ /* If there is no space available in this buffer,
+ allocate a new one. */
+ if (!BUFFER_BYTES_FREE (buffer)) {
+ status = (omapi_buffer_new (&buffer -> next, MDL));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ buffer = buffer -> next;
+ }
+
+ if (buffer -> tail > buffer -> head)
+ copy_len = sizeof (buffer -> buf) - buffer -> tail;
+ else
+ copy_len = buffer -> head - buffer -> tail;
+
+ if (copy_len > (len - bytes_copied))
+ copy_len = len - bytes_copied;
+
+ if (c -> out_key) {
+ if (!c -> out_context)
+ sig_flags |= SIG_MODE_INIT;
+ status = omapi_connection_sign_data
+ (sig_flags, c -> out_key, &c -> out_context,
+ &bufp [bytes_copied], copy_len,
+ (omapi_typed_data_t **)0);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ memcpy (&buffer -> buf [buffer -> tail],
+ &bufp [bytes_copied], copy_len);
+ buffer -> tail += copy_len;
+ c -> out_bytes += copy_len;
+ bytes_copied += copy_len;
+ if (buffer -> tail == sizeof buffer -> buf)
+ buffer -> tail = 0;
+ }
+ return ISC_R_SUCCESS;
+}
+
+/* Copy some bytes from the input buffer, and advance the input buffer
+ pointer beyond the bytes copied out. */
+
+isc_result_t omapi_connection_copyout (unsigned char *buf,
+ omapi_object_t *h,
+ unsigned size)
+{
+ unsigned bytes_remaining;
+ unsigned bytes_this_copy;
+ unsigned first_byte;
+ omapi_buffer_t *buffer;
+ unsigned char *bufp;
+ int sig_flags = SIG_MODE_UPDATE;
+ omapi_connection_object_t *c;
+ isc_result_t status;
+
+ if (!h || h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (size > c -> in_bytes)
+ return ISC_R_NOMORE;
+ bufp = buf;
+ bytes_remaining = size;
+ buffer = c -> inbufs;
+
+ while (bytes_remaining) {
+ if (!buffer)
+ return ISC_R_UNEXPECTED;
+ if (BYTES_IN_BUFFER (buffer)) {
+ if (buffer -> head == (sizeof buffer -> buf) - 1)
+ first_byte = 0;
+ else
+ first_byte = buffer -> head + 1;
+
+ if (first_byte > buffer -> tail) {
+ bytes_this_copy = (sizeof buffer -> buf -
+ first_byte);
+ } else {
+ bytes_this_copy =
+ buffer -> tail - first_byte;
+ }
+ if (bytes_this_copy > bytes_remaining)
+ bytes_this_copy = bytes_remaining;
+ if (bufp) {
+ if (c -> in_key) {
+ if (!c -> in_context)
+ sig_flags |= SIG_MODE_INIT;
+ status = omapi_connection_sign_data
+ (sig_flags,
+ c -> in_key,
+ &c -> in_context,
+ (unsigned char *)
+ &buffer -> buf [first_byte],
+ bytes_this_copy,
+ (omapi_typed_data_t **)0);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ memcpy (bufp, &buffer -> buf [first_byte],
+ bytes_this_copy);
+ bufp += bytes_this_copy;
+ }
+ bytes_remaining -= bytes_this_copy;
+ buffer -> head = first_byte + bytes_this_copy - 1;
+ c -> in_bytes -= bytes_this_copy;
+ }
+
+ if (!BYTES_IN_BUFFER (buffer))
+ buffer = buffer -> next;
+ }
+
+ /* Get rid of any input buffers that we emptied. */
+ buffer = (omapi_buffer_t *)0;
+ while (c -> inbufs &&
+ !BYTES_IN_BUFFER (c -> inbufs)) {
+ if (c -> inbufs -> next) {
+ omapi_buffer_reference (&buffer,
+ c -> inbufs -> next, MDL);
+ omapi_buffer_dereference (&c -> inbufs -> next, MDL);
+ }
+ omapi_buffer_dereference (&c -> inbufs, MDL);
+ if (buffer) {
+ omapi_buffer_reference
+ (&c -> inbufs, buffer, MDL);
+ omapi_buffer_dereference (&buffer, MDL);
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_writer (omapi_object_t *h)
+{
+ unsigned bytes_this_write;
+ int bytes_written;
+ unsigned first_byte;
+ omapi_buffer_t *buffer;
+ unsigned char *bufp;
+ omapi_connection_object_t *c;
+ isc_result_t status;
+
+ if (!h || h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ /* Already flushed... */
+ if (!c -> out_bytes)
+ return ISC_R_SUCCESS;
+
+ buffer = c -> outbufs;
+
+ while (c -> out_bytes) {
+ if (!buffer)
+ return ISC_R_UNEXPECTED;
+ if (BYTES_IN_BUFFER (buffer)) {
+ if (buffer -> head == (sizeof buffer -> buf) - 1)
+ first_byte = 0;
+ else
+ first_byte = buffer -> head + 1;
+
+ if (first_byte > buffer -> tail) {
+ bytes_this_write = (sizeof buffer -> buf -
+ first_byte);
+ } else {
+ bytes_this_write =
+ buffer -> tail - first_byte;
+ }
+ bytes_written = write (c -> socket,
+ &buffer -> buf [first_byte],
+ bytes_this_write);
+ /* If the write failed with EWOULDBLOCK or we wrote
+ zero bytes, a further write would block, so we have
+ flushed as much as we can for now. Other errors
+ are really errors. */
+ if (bytes_written < 0) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ return ISC_R_SUCCESS;
+ else if (errno == EPIPE)
+ return ISC_R_NOCONN;
+#ifdef EDQUOT
+ else if (errno == EFBIG || errno == EDQUOT)
+#else
+ else if (errno == EFBIG)
+#endif
+ return ISC_R_NORESOURCES;
+ else if (errno == ENOSPC)
+ return ISC_R_NOSPACE;
+ else if (errno == EIO)
+ return ISC_R_IOERROR;
+ else if (errno == EINVAL)
+ return ISC_R_INVALIDARG;
+ else if (errno == ECONNRESET)
+ return ISC_R_SHUTTINGDOWN;
+ else
+ return ISC_R_UNEXPECTED;
+ }
+ if (bytes_written == 0)
+ return ISC_R_SUCCESS;
+
+#if defined (TRACING)
+ if (trace_record ()) {
+ trace_iov_t iov [2];
+ int32_t connect_index;
+
+ connect_index = htonl (c -> index);
+
+ iov [0].buf = (char *)&connect_index;
+ iov [0].len = sizeof connect_index;
+ iov [1].buf = &buffer -> buf [buffer -> tail];
+ iov [1].len = bytes_written;
+
+ status = (trace_write_packet_iov
+ (trace_connection_input, 2, iov,
+ MDL));
+ if (status != ISC_R_SUCCESS) {
+ trace_stop ();
+ log_error ("trace %s output: %s",
+ "connection",
+ isc_result_totext (status));
+ }
+ }
+#endif
+
+ buffer -> head = first_byte + bytes_written - 1;
+ c -> out_bytes -= bytes_written;
+
+ /* If we didn't finish out the write, we filled the
+ O.S. output buffer and a further write would block,
+ so stop trying to flush now. */
+ if (bytes_written != bytes_this_write)
+ return ISC_R_SUCCESS;
+ }
+
+ if (!BYTES_IN_BUFFER (buffer))
+ buffer = buffer -> next;
+ }
+
+ /* Get rid of any output buffers we emptied. */
+ buffer = (omapi_buffer_t *)0;
+ while (c -> outbufs &&
+ !BYTES_IN_BUFFER (c -> outbufs)) {
+ if (c -> outbufs -> next) {
+ omapi_buffer_reference (&buffer,
+ c -> outbufs -> next, MDL);
+ omapi_buffer_dereference (&c -> outbufs -> next, MDL);
+ }
+ omapi_buffer_dereference (&c -> outbufs, MDL);
+ if (buffer) {
+ omapi_buffer_reference (&c -> outbufs, buffer, MDL);
+ omapi_buffer_dereference (&buffer, MDL);
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_get_uint32 (omapi_object_t *c,
+ u_int32_t *result)
+{
+ u_int32_t inbuf;
+ isc_result_t status;
+
+ status = omapi_connection_copyout ((unsigned char *)&inbuf,
+ c, sizeof inbuf);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ *result = ntohl (inbuf);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_put_uint32 (omapi_object_t *c,
+ u_int32_t value)
+{
+ u_int32_t inbuf;
+ isc_result_t status;
+
+ inbuf = htonl (value);
+
+ return omapi_connection_copyin (c, (unsigned char *)&inbuf,
+ sizeof inbuf);
+}
+
+isc_result_t omapi_connection_get_uint16 (omapi_object_t *c,
+ u_int16_t *result)
+{
+ u_int16_t inbuf;
+ isc_result_t status;
+
+ status = omapi_connection_copyout ((unsigned char *)&inbuf,
+ c, sizeof inbuf);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ *result = ntohs (inbuf);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_put_uint16 (omapi_object_t *c,
+ u_int32_t value)
+{
+ u_int16_t inbuf;
+ isc_result_t status;
+
+ inbuf = htons (value);
+
+ return omapi_connection_copyin (c, (unsigned char *)&inbuf,
+ sizeof inbuf);
+}
+
+isc_result_t omapi_connection_write_typed_data (omapi_object_t *c,
+ omapi_typed_data_t *data)
+{
+ isc_result_t status;
+ omapi_handle_t handle;
+
+ /* Null data is valid. */
+ if (!data)
+ return omapi_connection_put_uint32 (c, 0);
+
+ switch (data -> type) {
+ case omapi_datatype_int:
+ status = omapi_connection_put_uint32 (c, sizeof (u_int32_t));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ return omapi_connection_put_uint32 (c, ((u_int32_t)
+ (data -> u.integer)));
+
+ case omapi_datatype_string:
+ case omapi_datatype_data:
+ status = omapi_connection_put_uint32 (c, data -> u.buffer.len);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ if (data -> u.buffer.len)
+ return omapi_connection_copyin
+ (c, data -> u.buffer.value,
+ data -> u.buffer.len);
+ return ISC_R_SUCCESS;
+
+ case omapi_datatype_object:
+ if (data -> u.object) {
+ status = omapi_object_handle (&handle,
+ data -> u.object);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ } else
+ handle = 0;
+ status = omapi_connection_put_uint32 (c, sizeof handle);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ return omapi_connection_put_uint32 (c, handle);
+
+ }
+ return ISC_R_INVALIDARG;
+}
+
+isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name)
+{
+ isc_result_t status;
+ unsigned len = strlen (name);
+
+ status = omapi_connection_put_uint16 (c, len);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ return omapi_connection_copyin (c, (const unsigned char *)name, len);
+}
+
+isc_result_t omapi_connection_put_string (omapi_object_t *c,
+ const char *string)
+{
+ isc_result_t status;
+ unsigned len;
+
+ if (string)
+ len = strlen (string);
+ else
+ len = 0;
+
+ status = omapi_connection_put_uint32 (c, len);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ if (len)
+ return omapi_connection_copyin
+ (c, (const unsigned char *)string, len);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h)
+{
+ isc_result_t status;
+ omapi_handle_t handle;
+
+ if (h) {
+ status = omapi_object_handle (&handle, h);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ } else
+ handle = 0; /* The null handle. */
+ status = omapi_connection_put_uint32 (c, sizeof handle);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ return omapi_connection_put_uint32 (c, handle);
+}
diff --git a/contrib/isc-dhcp/omapip/connection.c b/contrib/isc-dhcp/omapip/connection.c
new file mode 100644
index 000000000000..77ce113d22fa
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/connection.c
@@ -0,0 +1,1026 @@
+/* connection.c
+
+ Subroutines for dealing with connections. */
+
+/*
+ * Copyright (c) 1999-2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+
+#if defined (TRACING)
+static void trace_connect_input (trace_type_t *, unsigned, char *);
+static void trace_connect_stop (trace_type_t *);
+static void trace_disconnect_input (trace_type_t *, unsigned, char *);
+static void trace_disconnect_stop (trace_type_t *);
+trace_type_t *trace_connect;
+trace_type_t *trace_disconnect;
+extern omapi_array_t *trace_listeners;
+#endif
+static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
+
+OMAPI_OBJECT_ALLOC (omapi_connection,
+ omapi_connection_object_t, omapi_type_connection)
+
+isc_result_t omapi_connect (omapi_object_t *c,
+ const char *server_name,
+ unsigned port)
+{
+ struct hostent *he;
+ unsigned i, hix;
+ omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
+ struct in_addr foo;
+ isc_result_t status;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connect(%s, port=%d)", server_name, port);
+#endif
+
+ if (!inet_aton (server_name, &foo)) {
+ /* If we didn't get a numeric address, try for a domain
+ name. It's okay for this call to block. */
+ he = gethostbyname (server_name);
+ if (!he)
+ return ISC_R_HOSTUNKNOWN;
+ for (i = 0; he -> h_addr_list [i]; i++)
+ ;
+ if (i == 0)
+ return ISC_R_HOSTUNKNOWN;
+ hix = i;
+
+ status = omapi_addr_list_new (&addrs, hix, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ for (i = 0; i < hix; i++) {
+ addrs -> addresses [i].addrtype = he -> h_addrtype;
+ addrs -> addresses [i].addrlen = he -> h_length;
+ memcpy (addrs -> addresses [i].address,
+ he -> h_addr_list [i],
+ (unsigned)he -> h_length);
+ addrs -> addresses [i].port = port;
+ }
+ } else {
+ status = omapi_addr_list_new (&addrs, 1, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ addrs -> addresses [0].addrtype = AF_INET;
+ addrs -> addresses [0].addrlen = sizeof foo;
+ memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
+ addrs -> addresses [0].port = port;
+ hix = 1;
+ }
+ status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
+ omapi_addr_list_dereference (&addrs, MDL);
+ return status;
+}
+
+isc_result_t omapi_connect_list (omapi_object_t *c,
+ omapi_addr_list_t *remote_addrs,
+ omapi_addr_t *local_addr)
+{
+ isc_result_t status;
+ omapi_connection_object_t *obj;
+ int flag;
+ struct sockaddr_in local_sin;
+#if defined (TRACING)
+ trace_addr_t *addrs;
+ u_int16_t naddrs;
+#endif
+
+ obj = (omapi_connection_object_t *)0;
+ status = omapi_connection_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
+ MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_connection_dereference (&obj, MDL);
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, c, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_connection_dereference (&obj, MDL);
+ return status;
+ }
+
+ /* Store the address list on the object. */
+ omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
+ obj -> cptr = 0;
+ obj -> state = omapi_connection_unconnected;
+
+#if defined (TRACING)
+ /* If we're playing back, don't actually try to connect - just leave
+ the object available for a subsequent connect or disconnect. */
+ if (!trace_playback ()) {
+#endif
+ /* Create a socket on which to communicate. */
+ obj -> socket =
+ socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (obj -> socket < 0) {
+ omapi_connection_dereference (&obj, MDL);
+ if (errno == EMFILE || errno == ENFILE
+ || errno == ENOBUFS)
+ return ISC_R_NORESOURCES;
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Set up the local address, if any. */
+ if (local_addr) {
+ /* Only do TCPv4 so far. */
+ if (local_addr -> addrtype != AF_INET) {
+ omapi_connection_dereference (&obj, MDL);
+ return ISC_R_INVALIDARG;
+ }
+ local_sin.sin_port = htons (local_addr -> port);
+ memcpy (&local_sin.sin_addr,
+ local_addr -> address,
+ local_addr -> addrlen);
+#if defined (HAVE_SA_LEN)
+ local_sin.sin_len = sizeof local_addr;
+#endif
+ local_sin.sin_family = AF_INET;
+ memset (&local_sin.sin_zero, 0,
+ sizeof local_sin.sin_zero);
+
+ if (bind (obj -> socket, (struct sockaddr *)&local_sin,
+ sizeof local_sin) < 0) {
+ omapi_object_dereference ((omapi_object_t **)
+ &obj, MDL);
+ if (errno == EADDRINUSE)
+ return ISC_R_ADDRINUSE;
+ if (errno == EADDRNOTAVAIL)
+ return ISC_R_ADDRNOTAVAIL;
+ if (errno == EACCES)
+ return ISC_R_NOPERM;
+ return ISC_R_UNEXPECTED;
+ }
+ obj -> local_addr = local_sin;
+ }
+
+#if defined (HAVE_SETFD)
+ if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
+ close (obj -> socket);
+ omapi_connection_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+#endif
+
+ /* Set the SO_REUSEADDR flag (this should not fail). */
+ flag = 1;
+ if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&flag, sizeof flag) < 0) {
+ omapi_connection_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Set the file to nonblocking mode. */
+ if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
+ omapi_connection_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+
+ status = (omapi_register_io_object
+ ((omapi_object_t *)obj,
+ 0, omapi_connection_writefd,
+ 0, omapi_connection_connect,
+ omapi_connection_reaper));
+ if (status != ISC_R_SUCCESS)
+ goto out;
+ status = omapi_connection_connect_internal ((omapi_object_t *)
+ obj);
+#if defined (TRACING)
+ }
+ omapi_connection_register (obj, MDL);
+#endif
+
+ out:
+ omapi_connection_dereference (&obj, MDL);
+ return status;
+}
+
+#if defined (TRACING)
+omapi_array_t *omapi_connections;
+
+OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t)
+
+void omapi_connection_trace_setup (void) {
+ trace_connect = trace_type_register ("connect", (void *)0,
+ trace_connect_input,
+ trace_connect_stop, MDL);
+ trace_disconnect = trace_type_register ("disconnect", (void *)0,
+ trace_disconnect_input,
+ trace_disconnect_stop, MDL);
+}
+
+void omapi_connection_register (omapi_connection_object_t *obj,
+ const char *file, int line)
+{
+ isc_result_t status;
+ trace_iov_t iov [6];
+ int iov_count = 0;
+ int32_t connect_index, listener_index;
+ static int32_t index;
+
+ if (!omapi_connections) {
+ status = omapi_connection_array_allocate (&omapi_connections,
+ file, line);
+ if (status != ISC_R_SUCCESS)
+ return;
+ }
+
+ status = omapi_connection_array_extend (omapi_connections, obj,
+ (int *)0, file, line);
+ if (status != ISC_R_SUCCESS) {
+ obj -> index = -1;
+ return;
+ }
+
+#if defined (TRACING)
+ if (trace_record ()) {
+ /* Connection registration packet:
+
+ int32_t index
+ int32_t listener_index [-1 means no listener]
+ u_int16_t remote_port
+ u_int16_t local_port
+ u_int32_t remote_addr
+ u_int32_t local_addr */
+
+ connect_index = htonl (index);
+ index++;
+ if (obj -> listener)
+ listener_index = htonl (obj -> listener -> index);
+ else
+ listener_index = htonl (-1);
+ iov [iov_count].buf = (char *)&connect_index;
+ iov [iov_count++].len = sizeof connect_index;
+ iov [iov_count].buf = (char *)&listener_index;
+ iov [iov_count++].len = sizeof listener_index;
+ iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
+ iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
+ iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
+ iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
+ iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
+ iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
+ iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
+ iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
+
+ status = trace_write_packet_iov (trace_connect,
+ iov_count, iov, file, line);
+ }
+#endif
+}
+
+static void trace_connect_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ struct sockaddr_in remote, local;
+ int32_t connect_index, listener_index;
+ char *s = buf;
+ omapi_connection_object_t *obj;
+ isc_result_t status;
+ int i;
+
+ if (length != ((sizeof connect_index) +
+ (sizeof remote.sin_port) +
+ (sizeof remote.sin_addr)) * 2) {
+ log_error ("Trace connect: invalid length %d", length);
+ return;
+ }
+
+ memset (&remote, 0, sizeof remote);
+ memset (&local, 0, sizeof local);
+ memcpy (&connect_index, s, sizeof connect_index);
+ s += sizeof connect_index;
+ memcpy (&listener_index, s, sizeof listener_index);
+ s += sizeof listener_index;
+ memcpy (&remote.sin_port, s, sizeof remote.sin_port);
+ s += sizeof remote.sin_port;
+ memcpy (&local.sin_port, s, sizeof local.sin_port);
+ s += sizeof local.sin_port;
+ memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
+ s += sizeof remote.sin_addr;
+ memcpy (&local.sin_addr, s, sizeof local.sin_addr);
+ s += sizeof local.sin_addr;
+
+ connect_index = ntohl (connect_index);
+ listener_index = ntohl (listener_index);
+
+ /* If this was a connect to a listener, then we just slap together
+ a new connection. */
+ if (listener_index != -1) {
+ omapi_listener_object_t *listener;
+ listener = (omapi_listener_object_t *)0;
+ omapi_array_foreach_begin (trace_listeners,
+ omapi_listener_object_t, lp) {
+ if (lp -> address.sin_port == local.sin_port) {
+ omapi_listener_reference (&listener, lp, MDL);
+ omapi_listener_dereference (&lp, MDL);
+ break;
+ }
+ } omapi_array_foreach_end (trace_listeners,
+ omapi_listener_object_t, lp);
+ if (!listener) {
+ log_error ("%s%ld, addr %s, port %d",
+ "Spurious traced listener connect - index ",
+ (long int)listener_index,
+ inet_ntoa (local.sin_addr),
+ ntohs (local.sin_port));
+ return;
+ }
+ obj = (omapi_connection_object_t *)0;
+ status = omapi_listener_connect (&obj, listener, -1, &remote);
+ if (status != ISC_R_SUCCESS) {
+ log_error ("traced listener connect: %s",
+ isc_result_totext (status));
+ }
+ if (obj)
+ omapi_connection_dereference (&obj, MDL);
+ omapi_listener_dereference (&listener, MDL);
+ return;
+ }
+
+ /* Find the matching connect object, if there is one. */
+ omapi_array_foreach_begin (omapi_connections,
+ omapi_connection_object_t, lp) {
+ for (i = 0; (lp -> connect_list &&
+ i < lp -> connect_list -> count); i++) {
+ if (!memcmp (&remote.sin_addr,
+ &lp -> connect_list -> addresses [i].address,
+ sizeof remote.sin_addr) &&
+ (ntohs (remote.sin_port) ==
+ lp -> connect_list -> addresses [i].port))
+ lp -> state = omapi_connection_connected;
+ lp -> remote_addr = remote;
+ lp -> remote_addr.sin_family = AF_INET;
+#if defined (HAVE_SIN_LEN)
+ lp -> remote_addr.sin_len = sizeof remote;
+#endif
+ omapi_addr_list_dereference (&lp -> connect_list, MDL);
+ lp -> index = connect_index;
+ status = omapi_signal_in ((omapi_object_t *)lp,
+ "connect");
+ omapi_connection_dereference (&lp, MDL);
+ return;
+ }
+ } omapi_array_foreach_end (omapi_connections,
+ omapi_connection_object_t, lp);
+
+ log_error ("Spurious traced connect - index %ld, addr %s, port %d",
+ (long int)connect_index, inet_ntoa (remote.sin_addr),
+ ntohs (remote.sin_port));
+ return;
+}
+
+static void trace_connect_stop (trace_type_t *ttype) { }
+
+static void trace_disconnect_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ int32_t *index;
+ if (length != sizeof *index) {
+ log_error ("trace disconnect: wrong length %d", length);
+ return;
+ }
+
+ index = (int32_t *)buf;
+
+ omapi_array_foreach_begin (omapi_connections,
+ omapi_connection_object_t, lp) {
+ if (lp -> index == ntohl (*index)) {
+ omapi_disconnect ((omapi_object_t *)lp, 1);
+ omapi_connection_dereference (&lp, MDL);
+ return;
+ }
+ } omapi_array_foreach_end (omapi_connections,
+ omapi_connection_object_t, lp);
+
+ log_error ("trace disconnect: no connection matching index %ld",
+ (long int)ntohl (*index));
+}
+
+static void trace_disconnect_stop (trace_type_t *ttype) { }
+#endif
+
+/* Disconnect a connection object from the remote end. If force is nonzero,
+ close the connection immediately. Otherwise, shut down the receiving end
+ but allow any unsent data to be sent before actually closing the socket. */
+
+isc_result_t omapi_disconnect (omapi_object_t *h,
+ int force)
+{
+ omapi_connection_object_t *c;
+ isc_result_t status;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_disconnect(%s)", force ? "force" : "");
+#endif
+
+ c = (omapi_connection_object_t *)h;
+ if (c -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+
+#if defined (TRACING)
+ if (trace_record ()) {
+ int32_t index;
+
+ index = htonl (c -> index);
+ status = trace_write_packet (trace_disconnect,
+ sizeof index, (char *)&index,
+ MDL);
+ if (status != ISC_R_SUCCESS) {
+ trace_stop ();
+ log_error ("trace_write_packet: %s",
+ isc_result_totext (status));
+ }
+ }
+ if (!trace_playback ()) {
+#endif
+ if (!force) {
+ /* If we're already disconnecting, we don't have to do
+ anything. */
+ if (c -> state == omapi_connection_disconnecting)
+ return ISC_R_SUCCESS;
+
+ /* Try to shut down the socket - this sends a FIN to
+ the remote end, so that it won't send us any more
+ data. If the shutdown succeeds, and we still
+ have bytes left to write, defer closing the socket
+ until that's done. */
+ if (!shutdown (c -> socket, SHUT_RD)) {
+ if (c -> out_bytes > 0) {
+ c -> state =
+ omapi_connection_disconnecting;
+ return ISC_R_SUCCESS;
+ }
+ }
+ }
+ close (c -> socket);
+#if defined (TRACING)
+ }
+#endif
+ c -> state = omapi_connection_closed;
+
+ /* Disconnect from I/O object, if any. */
+ if (h -> outer) {
+ if (h -> outer -> inner)
+ omapi_object_dereference (&h -> outer -> inner, MDL);
+ omapi_object_dereference (&h -> outer, MDL);
+ }
+
+ /* If whatever created us registered a signal handler, send it
+ a disconnect signal. */
+ omapi_signal (h, "disconnect", h);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
+{
+ omapi_connection_object_t *c;
+
+ if (h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ c -> bytes_needed = bytes;
+ if (c -> bytes_needed <= c -> in_bytes) {
+ return ISC_R_SUCCESS;
+ }
+ return ISC_R_NOTYET;
+}
+
+/* Return the socket on which the dispatcher should wait for readiness
+ to read, for a connection object. If we already have more bytes than
+ we need to do the next thing, and we have at least a single full input
+ buffer, then don't indicate that we're ready to read. */
+int omapi_connection_readfd (omapi_object_t *h)
+{
+ omapi_connection_object_t *c;
+ if (h -> type != omapi_type_connection)
+ return -1;
+ c = (omapi_connection_object_t *)h;
+ if (c -> state != omapi_connection_connected)
+ return -1;
+ if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
+ c -> in_bytes > c -> bytes_needed)
+ return -1;
+ return c -> socket;
+}
+
+/* Return the socket on which the dispatcher should wait for readiness
+ to write, for a connection object. If there are no bytes buffered
+ for writing, then don't indicate that we're ready to write. */
+int omapi_connection_writefd (omapi_object_t *h)
+{
+ omapi_connection_object_t *c;
+ if (h -> type != omapi_type_connection)
+ return -1;
+ c = (omapi_connection_object_t *)h;
+ if (c -> state == omapi_connection_connecting)
+ return c -> socket;
+ if (c -> out_bytes)
+ return c -> socket;
+ else
+ return -1;
+}
+
+isc_result_t omapi_connection_connect (omapi_object_t *h)
+{
+ isc_result_t status;
+
+ status = omapi_connection_connect_internal (h);
+ if (status != ISC_R_SUCCESS)
+ omapi_signal (h, "status", status);
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
+{
+ int error;
+ omapi_connection_object_t *c;
+ SOCKLEN_T sl;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (c -> state == omapi_connection_connecting) {
+ sl = sizeof error;
+ if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
+ (char *)&error, &sl) < 0) {
+ omapi_disconnect (h, 1);
+ return ISC_R_SUCCESS;
+ }
+ if (!error)
+ c -> state = omapi_connection_connected;
+ }
+ if (c -> state == omapi_connection_connecting ||
+ c -> state == omapi_connection_unconnected) {
+ if (c -> cptr >= c -> connect_list -> count) {
+ switch (error) {
+ case ECONNREFUSED:
+ status = ISC_R_CONNREFUSED;
+ break;
+ case ENETUNREACH:
+ status = ISC_R_NETUNREACH;
+ break;
+ default:
+ status = uerr2isc (error);
+ break;
+ }
+ omapi_disconnect (h, 1);
+ return status;
+ }
+
+ if (c -> connect_list -> addresses [c -> cptr].addrtype !=
+ AF_INET) {
+ omapi_disconnect (h, 1);
+ return ISC_R_INVALIDARG;
+ }
+
+ memcpy (&c -> remote_addr.sin_addr,
+ &c -> connect_list -> addresses [c -> cptr].address,
+ sizeof c -> remote_addr.sin_addr);
+ c -> remote_addr.sin_family = AF_INET;
+ c -> remote_addr.sin_port =
+ htons (c -> connect_list -> addresses [c -> cptr].port);
+#if defined (HAVE_SA_LEN)
+ c -> remote_addr.sin_len = sizeof c -> remote_addr;
+#endif
+ memset (&c -> remote_addr.sin_zero, 0,
+ sizeof c -> remote_addr.sin_zero);
+ ++c -> cptr;
+
+ error = connect (c -> socket,
+ (struct sockaddr *)&c -> remote_addr,
+ sizeof c -> remote_addr);
+ if (error < 0) {
+ error = errno;
+ if (error != EINPROGRESS) {
+ omapi_disconnect (h, 1);
+ switch (error) {
+ case ECONNREFUSED:
+ status = ISC_R_CONNREFUSED;
+ break;
+ case ENETUNREACH:
+ status = ISC_R_NETUNREACH;
+ break;
+ default:
+ status = uerr2isc (error);
+ break;
+ }
+ return status;
+ }
+ c -> state = omapi_connection_connecting;
+ return ISC_R_INCOMPLETE;
+ }
+ c -> state = omapi_connection_connected;
+ }
+
+ /* I don't know why this would fail, so I'm tempted not to test
+ the return value. */
+ sl = sizeof (c -> local_addr);
+ if (getsockname (c -> socket,
+ (struct sockaddr *)&c -> local_addr, &sl) < 0) {
+ }
+
+ /* Disconnect from I/O object, if any. */
+ if (h -> outer)
+ omapi_unregister_io_object (h);
+
+ status = omapi_register_io_object (h,
+ omapi_connection_readfd,
+ omapi_connection_writefd,
+ omapi_connection_reader,
+ omapi_connection_writer,
+ omapi_connection_reaper);
+
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (h, 1);
+ return status;
+ }
+
+ omapi_signal_in (h, "connect");
+ omapi_addr_list_dereference (&c -> connect_list, MDL);
+ return ISC_R_SUCCESS;
+}
+
+/* Reaper function for connection - if the connection is completely closed,
+ reap it. If it's in the disconnecting state, there were bytes left
+ to write when the user closed it, so if there are now no bytes left to
+ write, we can close it. */
+isc_result_t omapi_connection_reaper (omapi_object_t *h)
+{
+ omapi_connection_object_t *c;
+
+ if (h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+
+ c = (omapi_connection_object_t *)h;
+ if (c -> state == omapi_connection_disconnecting &&
+ c -> out_bytes == 0) {
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connection_reaper(): disconnect");
+#endif
+ omapi_disconnect (h, 1);
+ }
+ if (c -> state == omapi_connection_closed) {
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connection_reaper(): closed");
+#endif
+ return ISC_R_NOTCONNECTED;
+ }
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t make_dst_key (DST_KEY **dst_key, omapi_object_t *a) {
+ omapi_value_t *name = (omapi_value_t *)0;
+ omapi_value_t *algorithm = (omapi_value_t *)0;
+ omapi_value_t *key = (omapi_value_t *)0;
+ int algorithm_id;
+ char *name_str;
+ isc_result_t status = ISC_R_SUCCESS;
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_get_value_str
+ (a, (omapi_object_t *)0, "name", &name);
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_get_value_str
+ (a, (omapi_object_t *)0, "algorithm", &algorithm);
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_get_value_str
+ (a, (omapi_object_t *)0, "key", &key);
+
+ if (status == ISC_R_SUCCESS) {
+ if ((algorithm -> value -> type == omapi_datatype_data ||
+ algorithm -> value -> type == omapi_datatype_string) &&
+ strncasecmp ((char *)algorithm -> value -> u.buffer.value,
+ NS_TSIG_ALG_HMAC_MD5 ".",
+ algorithm -> value -> u.buffer.len) == 0) {
+ algorithm_id = KEY_HMAC_MD5;
+ } else {
+ status = ISC_R_INVALIDARG;
+ }
+ }
+
+ if (status == ISC_R_SUCCESS) {
+ name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL);
+ if (!name_str)
+ status = ISC_R_NOMEMORY;
+ }
+
+ if (status == ISC_R_SUCCESS) {
+ memcpy (name_str,
+ name -> value -> u.buffer.value,
+ name -> value -> u.buffer.len);
+ name_str [name -> value -> u.buffer.len] = 0;
+
+ *dst_key = dst_buffer_to_key (name_str, algorithm_id, 0, 0,
+ key -> value -> u.buffer.value,
+ key -> value -> u.buffer.len);
+ if (!*dst_key)
+ status = ISC_R_NOMEMORY;
+ }
+
+ if (name_str)
+ dfree (name_str, MDL);
+ if (key)
+ omapi_value_dereference (&key, MDL);
+ if (algorithm)
+ omapi_value_dereference (&algorithm, MDL);
+ if (name)
+ omapi_value_dereference (&name, MDL);
+
+ return status;
+}
+
+isc_result_t omapi_connection_sign_data (int mode,
+ DST_KEY *key,
+ void **context,
+ const unsigned char *data,
+ const unsigned len,
+ omapi_typed_data_t **result)
+{
+ omapi_typed_data_t *td = (omapi_typed_data_t *)0;
+ isc_result_t status;
+ int r;
+
+ if (mode & SIG_MODE_FINAL) {
+ status = omapi_typed_data_new (MDL, &td,
+ omapi_datatype_data,
+ dst_sig_size (key));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ r = dst_sign_data (mode, key, context, data, len,
+ td ? td -> u.buffer.value : (u_char *)0,
+ td ? td -> u.buffer.len : 0);
+
+ /* dst_sign_data() really should do this for us, shouldn't it? */
+ if (mode & SIG_MODE_FINAL)
+ *context = (void *)0;
+
+ if (r < 0) {
+ if (td)
+ omapi_typed_data_dereference (&td, MDL);
+ return ISC_R_INVALIDKEY;
+ }
+
+ if (result && td) {
+ omapi_typed_data_reference (result, td, MDL);
+ }
+
+ if (td)
+ omapi_typed_data_dereference (&td, MDL);
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_output_auth_length (omapi_object_t *h,
+ unsigned *l)
+{
+ omapi_connection_object_t *c;
+
+ if (h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (!c -> out_key)
+ return ISC_R_NOTFOUND;
+
+ *l = dst_sig_size (c -> out_key);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_connection_object_t *c;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
+ if (value && value -> type != omapi_datatype_object)
+ return ISC_R_INVALIDARG;
+
+ if (c -> in_context) {
+ omapi_connection_sign_data (SIG_MODE_FINAL,
+ c -> in_key,
+ &c -> in_context,
+ 0, 0,
+ (omapi_typed_data_t **) 0);
+ }
+
+ if (c -> in_key) {
+ dst_free_key (c -> in_key);
+ c -> in_key = (DST_KEY *)0;
+ }
+
+ if (value) {
+ status = make_dst_key (&c -> in_key,
+ value -> u.object);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ return ISC_R_SUCCESS;
+ }
+ else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
+ if (value && value -> type != omapi_datatype_object)
+ return ISC_R_INVALIDARG;
+
+ if (c -> out_context) {
+ omapi_connection_sign_data (SIG_MODE_FINAL,
+ c -> out_key,
+ &c -> out_context,
+ 0, 0,
+ (omapi_typed_data_t **) 0);
+ }
+
+ if (c -> out_key) {
+ dst_free_key (c -> out_key);
+ c -> out_key = (DST_KEY *)0;
+ }
+
+ if (value) {
+ status = make_dst_key (&c -> out_key,
+ value -> u.object);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ return ISC_R_SUCCESS;
+ }
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_connection_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_connection_object_t *c;
+ omapi_typed_data_t *td = (omapi_typed_data_t *)0;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = (omapi_connection_object_t *)h;
+
+ if (omapi_ds_strcmp (name, "input-signature") == 0) {
+ if (!c -> in_key || !c -> in_context)
+ return ISC_R_NOTFOUND;
+
+ status = omapi_connection_sign_data (SIG_MODE_FINAL,
+ c -> in_key,
+ &c -> in_context,
+ 0, 0, &td);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_make_value (value, name, td, MDL);
+ omapi_typed_data_dereference (&td, MDL);
+ return status;
+
+ } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
+ if (!c -> in_key)
+ return ISC_R_NOTFOUND;
+
+ return omapi_make_int_value (value, name,
+ dst_sig_size (c -> in_key), MDL);
+
+ } else if (omapi_ds_strcmp (name, "output-signature") == 0) {
+ if (!c -> out_key || !c -> out_context)
+ return ISC_R_NOTFOUND;
+
+ status = omapi_connection_sign_data (SIG_MODE_FINAL,
+ c -> out_key,
+ &c -> out_context,
+ 0, 0, &td);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_make_value (value, name, td, MDL);
+ omapi_typed_data_dereference (&td, MDL);
+ return status;
+
+ } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
+ if (!c -> out_key)
+ return ISC_R_NOTFOUND;
+
+ return omapi_make_int_value (value, name,
+ dst_sig_size (c -> out_key), MDL);
+ }
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_connection_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_connection_object_t *c;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connection_destroy()");
+#endif
+
+ if (h -> type != omapi_type_connection)
+ return ISC_R_UNEXPECTED;
+ c = (omapi_connection_object_t *)(h);
+ if (c -> state == omapi_connection_connected)
+ omapi_disconnect (h, 1);
+ if (c -> listener)
+ omapi_listener_dereference (&c -> listener, file, line);
+ if (c -> connect_list)
+ omapi_addr_list_dereference (&c -> connect_list, file, line);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_connection_signal_handler(%s)", name);
+#endif
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *m)
+{
+ int i;
+
+ if (m -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+
+ if (m -> inner && m -> inner -> type -> stuff_values)
+ return (*(m -> inner -> type -> stuff_values)) (c, id,
+ m -> inner);
+ return ISC_R_SUCCESS;
+}
diff --git a/contrib/isc-dhcp/omapip/convert.c b/contrib/isc-dhcp/omapip/convert.c
new file mode 100644
index 000000000000..83d5fc3b292a
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/convert.c
@@ -0,0 +1,193 @@
+/* convert.c
+
+ Safe copying of option values into and out of the option buffer, which
+ can't be assumed to be aligned. */
+
+/*
+ * Copyright (c) 1996-1999 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: convert.c,v 1.1 2000/08/01 22:34:36 neild Exp $ Copyright (c) 1996-1999 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include <omapip/omapip_p.h>
+
+u_int32_t getULong (buf)
+ const unsigned char *buf;
+{
+ unsigned long ibuf;
+
+ memcpy (&ibuf, buf, sizeof (u_int32_t));
+ return ntohl (ibuf);
+}
+
+int32_t getLong (buf)
+ const unsigned char *buf;
+{
+ long ibuf;
+
+ memcpy (&ibuf, buf, sizeof (int32_t));
+ return ntohl (ibuf);
+}
+
+u_int32_t getUShort (buf)
+ const unsigned char *buf;
+{
+ unsigned short ibuf;
+
+ memcpy (&ibuf, buf, sizeof (u_int16_t));
+ return ntohs (ibuf);
+}
+
+int32_t getShort (buf)
+ const unsigned char *buf;
+{
+ short ibuf;
+
+ memcpy (&ibuf, buf, sizeof (int16_t));
+ return ntohs (ibuf);
+}
+
+void putULong (obuf, val)
+ unsigned char *obuf;
+ u_int32_t val;
+{
+ u_int32_t tmp = htonl (val);
+ memcpy (obuf, &tmp, sizeof tmp);
+}
+
+void putLong (obuf, val)
+ unsigned char *obuf;
+ int32_t val;
+{
+ int32_t tmp = htonl (val);
+ memcpy (obuf, &tmp, sizeof tmp);
+}
+
+void putUShort (obuf, val)
+ unsigned char *obuf;
+ u_int32_t val;
+{
+ u_int16_t tmp = htons (val);
+ memcpy (obuf, &tmp, sizeof tmp);
+}
+
+void putShort (obuf, val)
+ unsigned char *obuf;
+ int32_t val;
+{
+ int16_t tmp = htons (val);
+ memcpy (obuf, &tmp, sizeof tmp);
+}
+
+void putUChar (obuf, val)
+ unsigned char *obuf;
+ u_int32_t val;
+{
+ *obuf = val;
+}
+
+u_int32_t getUChar (obuf)
+ const unsigned char *obuf;
+{
+ return obuf [0];
+}
+
+int converted_length (buf, base, width)
+ const unsigned char *buf;
+ unsigned int base;
+ unsigned int width;
+{
+ u_int32_t number;
+ u_int32_t column;
+ int power = 1;
+ u_int32_t newcolumn = base;
+
+ if (base > 16)
+ return 0;
+
+ if (width == 1)
+ number = getUChar (buf);
+ else if (width == 2)
+ number = getUShort (buf);
+ else if (width == 4)
+ number = getULong (buf);
+
+ do {
+ column = newcolumn;
+
+ if (number < column)
+ return power;
+ power++;
+ newcolumn = column * base;
+ /* If we wrap around, it must be the next power of two up. */
+ } while (newcolumn > column);
+
+ return power;
+}
+
+int binary_to_ascii (outbuf, inbuf, base, width)
+ unsigned char *outbuf;
+ const unsigned char *inbuf;
+ unsigned int base;
+ unsigned int width;
+{
+ u_int32_t number;
+ static char h2a [] = "0123456789abcdef";
+ int power = converted_length (inbuf, base, width);
+ int i, j;
+
+ if (base > 16)
+ return 0;
+
+ if (width == 1)
+ number = getUChar (inbuf);
+ else if (width == 2)
+ number = getUShort (inbuf);
+ else if (width == 4)
+ number = getULong (inbuf);
+
+ for (i = power - 1 ; i >= 0; i--) {
+ outbuf [i] = h2a [number % base];
+ number /= base;
+ }
+
+ return power;
+}
diff --git a/contrib/isc-dhcp/omapip/dispatch.c b/contrib/isc-dhcp/omapip/dispatch.c
new file mode 100644
index 000000000000..02bab7cc3019
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/dispatch.c
@@ -0,0 +1,604 @@
+/* dispatch.c
+
+ I/O dispatcher. */
+
+/*
+ * Copyright (c) 1999-2000 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+static omapi_io_object_t omapi_io_states;
+u_int32_t cur_time;
+
+OMAPI_OBJECT_ALLOC (omapi_io,
+ omapi_io_object_t, omapi_type_io_object)
+OMAPI_OBJECT_ALLOC (omapi_waiter,
+ omapi_waiter_object_t, omapi_type_waiter)
+
+/* Register an I/O handle so that we can do asynchronous I/O on it. */
+
+isc_result_t omapi_register_io_object (omapi_object_t *h,
+ int (*readfd) (omapi_object_t *),
+ int (*writefd) (omapi_object_t *),
+ isc_result_t (*reader)
+ (omapi_object_t *),
+ isc_result_t (*writer)
+ (omapi_object_t *),
+ isc_result_t (*reaper)
+ (omapi_object_t *))
+{
+ isc_result_t status;
+ omapi_io_object_t *obj, *p;
+
+ /* omapi_io_states is a static object. If its reference count
+ is zero, this is the first I/O handle to be registered, so
+ we need to initialize it. Because there is no inner or outer
+ pointer on this object, and we're setting its refcnt to 1, it
+ will never be freed. */
+ if (!omapi_io_states.refcnt) {
+ omapi_io_states.refcnt = 1;
+ omapi_io_states.type = omapi_type_io_object;
+ }
+
+ obj = (omapi_io_object_t *)0;
+ status = omapi_io_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_reference (&obj -> inner, h, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_io_dereference (&obj, MDL);
+ return status;
+ }
+
+ status = omapi_object_reference (&h -> outer,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_io_dereference (&obj, MDL);
+ return status;
+ }
+
+ /* Find the last I/O state, if there are any. */
+ for (p = omapi_io_states.next;
+ p && p -> next; p = p -> next)
+ ;
+ if (p)
+ omapi_io_reference (&p -> next, obj, MDL);
+ else
+ omapi_io_reference (&omapi_io_states.next, obj, MDL);
+
+ obj -> readfd = readfd;
+ obj -> writefd = writefd;
+ obj -> reader = reader;
+ obj -> writer = writer;
+ obj -> reaper = reaper;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_unregister_io_object (omapi_object_t *h)
+{
+ omapi_io_object_t *p, *obj, *last, *ph;
+
+ if (!h -> outer || h -> outer -> type != omapi_type_io_object)
+ return ISC_R_INVALIDARG;
+ obj = (omapi_io_object_t *)h -> outer;
+ ph = (omapi_io_object_t *)0;
+ omapi_io_reference (&ph, obj, MDL);
+
+ /* remove from the list of I/O states */
+ last = &omapi_io_states;
+ for (p = omapi_io_states.next; p; p = p -> next) {
+ if (p == obj) {
+ omapi_io_dereference (&last -> next, MDL);
+ omapi_io_reference (&last -> next, p -> next, MDL);
+ break;
+ }
+ last = p;
+ }
+ if (obj -> next)
+ omapi_io_dereference (&obj -> next, MDL);
+
+ if (obj -> outer) {
+ if (obj -> outer -> inner == (omapi_object_t *)obj)
+ omapi_object_dereference (&obj -> outer -> inner,
+ MDL);
+ omapi_object_dereference (&obj -> outer, MDL);
+ }
+ omapi_object_dereference (&obj -> inner, MDL);
+ omapi_object_dereference (&h -> outer, MDL);
+ omapi_io_dereference (&ph, MDL);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_dispatch (struct timeval *t)
+{
+ return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states,
+ t);
+}
+
+isc_result_t omapi_wait_for_completion (omapi_object_t *object,
+ struct timeval *t)
+{
+ isc_result_t status;
+ omapi_waiter_object_t *waiter;
+ omapi_object_t *inner;
+
+ if (object) {
+ waiter = (omapi_waiter_object_t *)0;
+ status = omapi_waiter_allocate (&waiter, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ /* Paste the waiter object onto the inner object we're
+ waiting on. */
+ for (inner = object; inner -> inner; inner = inner -> inner)
+ ;
+
+ status = omapi_object_reference (&waiter -> outer, inner, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_waiter_dereference (&waiter, MDL);
+ return status;
+ }
+
+ status = omapi_object_reference (&inner -> inner,
+ (omapi_object_t *)waiter,
+ MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_waiter_dereference (&waiter, MDL);
+ return status;
+ }
+ } else
+ waiter = (omapi_waiter_object_t *)0;
+
+ do {
+ status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ } while (!waiter || !waiter -> ready);
+
+ if (waiter -> outer) {
+ if (waiter -> outer -> inner) {
+ omapi_object_dereference (&waiter -> outer -> inner,
+ MDL);
+ if (waiter -> inner)
+ omapi_object_reference
+ (&waiter -> outer -> inner,
+ waiter -> inner, MDL);
+ }
+ omapi_object_dereference (&waiter -> outer, MDL);
+ }
+ if (waiter -> inner)
+ omapi_object_dereference (&waiter -> inner, MDL);
+
+ status = waiter -> waitstatus;
+ omapi_waiter_dereference (&waiter, MDL);
+ return status;
+}
+
+isc_result_t omapi_one_dispatch (omapi_object_t *wo,
+ struct timeval *t)
+{
+ fd_set r, w, x;
+ int max = 0;
+ int count;
+ int desc;
+ struct timeval now, to;
+ omapi_io_object_t *io, *prev;
+ isc_result_t status;
+ omapi_waiter_object_t *waiter;
+ omapi_object_t *tmp = (omapi_object_t *)0;
+
+ if (!wo || wo -> type != omapi_type_waiter)
+ waiter = (omapi_waiter_object_t *)0;
+ else
+ waiter = (omapi_waiter_object_t *)wo;
+
+ FD_ZERO (&x);
+
+ /* First, see if the timeout has expired, and if so return. */
+ if (t) {
+ gettimeofday (&now, (struct timezone *)0);
+ cur_time = now.tv_sec;
+ if (now.tv_sec > t -> tv_sec ||
+ (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec))
+ return ISC_R_TIMEDOUT;
+
+ /* We didn't time out, so figure out how long until
+ we do. */
+ to.tv_sec = t -> tv_sec - now.tv_sec;
+ to.tv_usec = t -> tv_usec - now.tv_usec;
+ if (to.tv_usec < 0) {
+ to.tv_usec += 1000000;
+ to.tv_sec--;
+ }
+
+ /* It is possible for the timeout to get set larger than
+ the largest time select() is willing to accept.
+ Restricting the timeout to a maximum of one day should
+ work around this. -DPN. (Ref: Bug #416) */
+ if (to.tv_sec > (60 * 60 * 24))
+ to.tv_sec = 60 * 60 * 24;
+ }
+
+ /* If the object we're waiting on has reached completion,
+ return now. */
+ if (waiter && waiter -> ready)
+ return ISC_R_SUCCESS;
+
+ again:
+ /* If we have no I/O state, we can't proceed. */
+ if (!(io = omapi_io_states.next))
+ return ISC_R_NOMORE;
+
+ /* Set up the read and write masks. */
+ FD_ZERO (&r);
+ FD_ZERO (&w);
+
+ for (; io; io = io -> next) {
+ /* Check for a read socket. If we shouldn't be
+ trying to read for this I/O object, either there
+ won't be a readfd function, or it'll return -1. */
+ if (io -> readfd && io -> inner &&
+ (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &r);
+ if (desc > max)
+ max = desc;
+ }
+
+ /* Same deal for write fdets. */
+ if (io -> writefd && io -> inner &&
+ (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &w);
+ if (desc > max)
+ max = desc;
+ }
+ }
+
+ /* Wait for a packet or a timeout... XXX */
+#if 0
+#if defined (__linux__)
+#define fds_bits __fds_bits
+#endif
+ log_error ("dispatch: %d %lx %lx", max,
+ (unsigned long)r.fds_bits [0],
+ (unsigned long)w.fds_bits [0]);
+#endif
+ count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0);
+
+ /* Get the current time... */
+ gettimeofday (&now, (struct timezone *)0);
+ cur_time = now.tv_sec;
+
+ /* We probably have a bad file descriptor. Figure out which one.
+ When we find it, call the reaper function on it, which will
+ maybe make it go away, and then try again. */
+ if (count < 0) {
+ struct timeval t0;
+ omapi_io_object_t *prev = (omapi_io_object_t *)0;
+ io = (omapi_io_object_t *)0;
+ if (omapi_io_states.next)
+ omapi_io_reference (&io, omapi_io_states.next, MDL);
+
+ while (io) {
+ omapi_object_t *obj;
+ FD_ZERO (&r);
+ FD_ZERO (&w);
+ t0.tv_sec = t0.tv_usec = 0;
+
+ if (io -> readfd && io -> inner &&
+ (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &r);
+#if 0
+ log_error ("read check: %d %lx %lx", max,
+ (unsigned long)r.fds_bits [0],
+ (unsigned long)w.fds_bits [0]);
+#endif
+ count = select (desc + 1, &r, &w, &x, &t0);
+ bogon:
+ if (count < 0) {
+ log_error ("Bad descriptor %d.", desc);
+ for (obj = (omapi_object_t *)io;
+ obj -> outer;
+ obj = obj -> outer)
+ ;
+ for (; obj; obj = obj -> inner) {
+ omapi_value_t *ov;
+ int len;
+ const char *s;
+ ov = (omapi_value_t *)0;
+ omapi_get_value_str (obj,
+ (omapi_object_t *)0,
+ "name", &ov);
+ if (ov && ov -> value &&
+ (ov -> value -> type ==
+ omapi_datatype_string)) {
+ s = (char *)
+ ov -> value -> u.buffer.value;
+ len = ov -> value -> u.buffer.len;
+ } else {
+ s = "";
+ len = 0;
+ }
+ log_error ("Object %lx %s%s%.*s",
+ (unsigned long)obj,
+ obj -> type -> name,
+ len ? " " : "",
+ len, s);
+ if (len)
+ omapi_value_dereference (&ov, MDL);
+ }
+ status = (*(io -> reaper)) (io -> inner);
+ if (prev) {
+ omapi_io_dereference (&prev -> next, MDL);
+ if (io -> next)
+ omapi_io_reference (&prev -> next,
+ io -> next, MDL);
+ } else {
+ omapi_io_dereference
+ (&omapi_io_states.next, MDL);
+ if (io -> next)
+ omapi_io_reference
+ (&omapi_io_states.next,
+ io -> next, MDL);
+ }
+ omapi_io_dereference (&io, MDL);
+ goto again;
+ }
+ }
+
+ FD_ZERO (&r);
+ FD_ZERO (&w);
+ t0.tv_sec = t0.tv_usec = 0;
+
+ /* Same deal for write fdets. */
+ if (io -> writefd && io -> inner &&
+ (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &w);
+ count = select (desc + 1, &r, &w, &x, &t0);
+ if (count < 0)
+ goto bogon;
+ }
+ if (prev)
+ omapi_io_dereference (&prev, MDL);
+ omapi_io_reference (&prev, io, MDL);
+ omapi_io_dereference (&io, MDL);
+ if (prev -> next)
+ omapi_io_reference (&io, prev -> next, MDL);
+ }
+ if (prev)
+ omapi_io_dereference (&prev, MDL);
+
+ }
+
+ for (io = omapi_io_states.next; io; io = io -> next) {
+ if (!io -> inner)
+ continue;
+ omapi_object_reference (&tmp, io -> inner, MDL);
+ /* Check for a read descriptor, and if there is one,
+ see if we got input on that socket. */
+ if (io -> readfd &&
+ (desc = (*(io -> readfd)) (tmp)) >= 0) {
+ if (FD_ISSET (desc, &r))
+ status = ((*(io -> reader)) (tmp));
+ /* XXX what to do with status? */
+ }
+
+ /* Same deal for write descriptors. */
+ if (io -> writefd &&
+ (desc = (*(io -> writefd)) (tmp)) >= 0)
+ {
+ if (FD_ISSET (desc, &w))
+ status = ((*(io -> writer)) (tmp));
+ /* XXX what to do with status? */
+ }
+ omapi_object_dereference (&tmp, MDL);
+ }
+
+ /* Now check for I/O handles that are no longer valid,
+ and remove them from the list. */
+ prev = (omapi_io_object_t *)0;
+ for (io = omapi_io_states.next; io; io = io -> next) {
+ if (io -> reaper) {
+ if (io -> inner)
+ status = (*(io -> reaper)) (io -> inner);
+ if (!io -> inner || status != ISC_R_SUCCESS) {
+ omapi_io_object_t *tmp =
+ (omapi_io_object_t *)0;
+ /* Save a reference to the next
+ pointer, if there is one. */
+ if (io -> next)
+ omapi_io_reference (&tmp,
+ io -> next, MDL);
+ if (prev) {
+ omapi_io_dereference (&prev -> next,
+ MDL);
+ if (tmp)
+ omapi_io_reference
+ (&prev -> next,
+ tmp, MDL);
+ } else {
+ omapi_io_dereference
+ (&omapi_io_states.next, MDL);
+ if (tmp)
+ omapi_io_reference
+ (&omapi_io_states.next,
+ tmp, MDL);
+ else
+ omapi_signal_in
+ ((omapi_object_t *)
+ &omapi_io_states,
+ "ready");
+ }
+ if (tmp)
+ omapi_io_dereference (&tmp, MDL);
+ }
+ }
+ prev = io;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_io_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ if (h -> type != omapi_type_io_object)
+ return ISC_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_io_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ if (h -> type != omapi_type_io_object)
+ return ISC_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line)
+{
+ omapi_io_object_t *obj, *p, *last;
+
+ if (h -> type != omapi_type_io_object)
+ return ISC_R_INVALIDARG;
+
+ obj = (omapi_io_object_t *)h;
+
+ /* remove from the list of I/O states */
+ for (p = omapi_io_states.next; p; p = p -> next) {
+ if (p == obj) {
+ omapi_io_dereference (&last -> next, MDL);
+ omapi_io_reference (&last -> next, p -> next, MDL);
+ omapi_io_dereference (&p, MDL);
+ break;
+ }
+ last = p;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_io_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != omapi_type_io_object)
+ return ISC_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_io_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *i)
+{
+ if (i -> type != omapi_type_io_object)
+ return ISC_R_INVALIDARG;
+
+ if (i -> inner && i -> inner -> type -> stuff_values)
+ return (*(i -> inner -> type -> stuff_values)) (c, id,
+ i -> inner);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_waiter_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ omapi_waiter_object_t *waiter;
+
+ if (h -> type != omapi_type_waiter)
+ return ISC_R_INVALIDARG;
+
+ if (!strcmp (name, "ready")) {
+ waiter = (omapi_waiter_object_t *)h;
+ waiter -> ready = 1;
+ waiter -> waitstatus = ISC_R_SUCCESS;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!strcmp (name, "status")) {
+ waiter = (omapi_waiter_object_t *)h;
+ waiter -> ready = 1;
+ waiter -> waitstatus = va_arg (ap, isc_result_t);
+ return ISC_R_SUCCESS;
+ }
+
+ if (!strcmp (name, "disconnect")) {
+ waiter = (omapi_waiter_object_t *)h;
+ waiter -> ready = 1;
+ waiter -> waitstatus = ISC_R_CONNRESET;
+ return ISC_R_SUCCESS;
+ }
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *,
+ void *),
+ void *p)
+{
+ omapi_io_object_t *io;
+ isc_result_t status;
+
+ for (io = omapi_io_states.next; io; io = io -> next) {
+ if (io -> inner) {
+ status = (*func) (io -> inner, p);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ }
+ return ISC_R_SUCCESS;
+}
diff --git a/contrib/isc-dhcp/omapip/errwarn.c b/contrib/isc-dhcp/omapip/errwarn.c
new file mode 100644
index 000000000000..6dc6dd967d9b
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/errwarn.c
@@ -0,0 +1,363 @@
+/* errwarn.c
+
+ Errors and warnings... */
+
+/*
+ * Copyright (c) 1995 RadioMail Corporation.
+ * Copyright (c) 1996-2000 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software was written for RadioMail Corporation by Ted Lemon
+ * under a contract with Vixie Enterprises. Further modifications have
+ * been made for the Internet Software Consortium under a contract
+ * with Vixie Laboratories.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: errwarn.c,v 1.9 2000/09/29 20:01:49 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include <omapip/omapip_p.h>
+#include <errno.h>
+
+#ifdef DEBUG
+int log_perror = -1;
+#else
+int log_perror = 1;
+#endif
+int log_priority;
+void (*log_cleanup) (void);
+
+#define CVT_BUF_MAX 1023
+static char mbuf [CVT_BUF_MAX + 1];
+static char fbuf [CVT_BUF_MAX + 1];
+
+/* Log an error message, then exit... */
+
+void log_fatal (const char * fmt, ... )
+{
+ va_list list;
+
+ do_percentm (fbuf, fmt);
+
+ va_start (list, fmt);
+ vsnprintf (mbuf, sizeof mbuf, fbuf, list);
+ va_end (list);
+
+#ifndef DEBUG
+ syslog (log_priority | LOG_ERR, "%s", mbuf);
+#endif
+
+ /* Also log it to stderr? */
+ if (log_perror) {
+ write (2, mbuf, strlen (mbuf));
+ write (2, "\n", 1);
+ }
+
+#if !defined (NOMINUM)
+ log_error ("%s", "");
+ log_error ("If you did not get this software from ftp.isc.org, please");
+ log_error ("get the latest from ftp.isc.org and install that before");
+ log_error ("requesting help.");
+ log_error ("%s", "");
+ log_error ("If you did get this software from ftp.isc.org and have not");
+ log_error ("yet read the README, please read it before requesting help.");
+ log_error ("If you intend to request help from the dhcp-server@isc.org");
+ log_error ("mailing list, please read the section on the README about");
+ log_error ("submitting bug reports and requests for help.");
+ log_error ("%s", "");
+ log_error ("Please do not under any circumstances send requests for");
+ log_error ("help directly to the authors of this software - please");
+ log_error ("send them to the appropriate mailing list as described in");
+ log_error ("the README file.");
+ log_error ("%s", "");
+ log_error ("exiting.");
+#endif
+ if (log_cleanup)
+ (*log_cleanup) ();
+ exit (1);
+}
+
+/* Log an error message... */
+
+int log_error (const char * fmt, ...)
+{
+ va_list list;
+
+ do_percentm (fbuf, fmt);
+
+ va_start (list, fmt);
+ vsnprintf (mbuf, sizeof mbuf, fbuf, list);
+ va_end (list);
+
+#ifndef DEBUG
+ syslog (log_priority | LOG_ERR, "%s", mbuf);
+#endif
+
+ if (log_perror) {
+ write (2, mbuf, strlen (mbuf));
+ write (2, "\n", 1);
+ }
+
+ return 0;
+}
+
+/* Log a note... */
+
+int log_info (const char *fmt, ...)
+{
+ va_list list;
+
+ do_percentm (fbuf, fmt);
+
+ va_start (list, fmt);
+ vsnprintf (mbuf, sizeof mbuf, fbuf, list);
+ va_end (list);
+
+#ifndef DEBUG
+ syslog (log_priority | LOG_INFO, "%s", mbuf);
+#endif
+
+ if (log_perror) {
+ write (2, mbuf, strlen (mbuf));
+ write (2, "\n", 1);
+ }
+
+ return 0;
+}
+
+/* Log a debug message... */
+
+int log_debug (const char *fmt, ...)
+{
+ va_list list;
+
+ do_percentm (fbuf, fmt);
+
+ va_start (list, fmt);
+ vsnprintf (mbuf, sizeof mbuf, fbuf, list);
+ va_end (list);
+
+#ifndef DEBUG
+ syslog (log_priority | LOG_DEBUG, "%s", mbuf);
+#endif
+
+ if (log_perror) {
+ write (2, mbuf, strlen (mbuf));
+ write (2, "\n", 1);
+ }
+
+ return 0;
+}
+
+/* Find %m in the input string and substitute an error message string. */
+
+void do_percentm (obuf, ibuf)
+ char *obuf;
+ const char *ibuf;
+{
+ const char *s = ibuf;
+ char *p = obuf;
+ int infmt = 0;
+ const char *m;
+ int len = 0;
+
+ while (*s) {
+ if (infmt) {
+ if (*s == 'm') {
+#ifndef __CYGWIN32__
+ m = strerror (errno);
+#else
+ m = pWSAError ();
+#endif
+ if (!m)
+ m = "<unknown error>";
+ len += strlen (m);
+ if (len > CVT_BUF_MAX)
+ goto out;
+ strcpy (p - 1, m);
+ p += strlen (p);
+ ++s;
+ } else {
+ if (++len > CVT_BUF_MAX)
+ goto out;
+ *p++ = *s++;
+ }
+ infmt = 0;
+ } else {
+ if (*s == '%')
+ infmt = 1;
+ if (++len > CVT_BUF_MAX)
+ goto out;
+ *p++ = *s++;
+ }
+ }
+ out:
+ *p = 0;
+}
+
+#ifdef NO_STRERROR
+char *strerror (err)
+ int err;
+{
+ extern char *sys_errlist [];
+ extern int sys_nerr;
+ static char errbuf [128];
+
+ if (err < 0 || err >= sys_nerr) {
+ sprintf (errbuf, "Error %d", err);
+ return errbuf;
+ }
+ return sys_errlist [err];
+}
+#endif /* NO_STRERROR */
+
+#ifdef _WIN32
+char *pWSAError ()
+{
+ int err = WSAGetLastError ();
+
+ switch (err)
+ {
+ case WSAEACCES:
+ return "Permission denied";
+ case WSAEADDRINUSE:
+ return "Address already in use";
+ case WSAEADDRNOTAVAIL:
+ return "Cannot assign requested address";
+ case WSAEAFNOSUPPORT:
+ return "Address family not supported by protocol family";
+ case WSAEALREADY:
+ return "Operation already in progress";
+ case WSAECONNABORTED:
+ return "Software caused connection abort";
+ case WSAECONNREFUSED:
+ return "Connection refused";
+ case WSAECONNRESET:
+ return "Connection reset by peer";
+ case WSAEDESTADDRREQ:
+ return "Destination address required";
+ case WSAEFAULT:
+ return "Bad address";
+ case WSAEHOSTDOWN:
+ return "Host is down";
+ case WSAEHOSTUNREACH:
+ return "No route to host";
+ case WSAEINPROGRESS:
+ return "Operation now in progress";
+ case WSAEINTR:
+ return "Interrupted function call";
+ case WSAEINVAL:
+ return "Invalid argument";
+ case WSAEISCONN:
+ return "Socket is already connected";
+ case WSAEMFILE:
+ return "Too many open files";
+ case WSAEMSGSIZE:
+ return "Message too long";
+ case WSAENETDOWN:
+ return "Network is down";
+ case WSAENETRESET:
+ return "Network dropped connection on reset";
+ case WSAENETUNREACH:
+ return "Network is unreachable";
+ case WSAENOBUFS:
+ return "No buffer space available";
+ case WSAENOPROTOOPT:
+ return "Bad protocol option";
+ case WSAENOTCONN:
+ return "Socket is not connected";
+ case WSAENOTSOCK:
+ return "Socket operation on non-socket";
+ case WSAEOPNOTSUPP:
+ return "Operation not supported";
+ case WSAEPFNOSUPPORT:
+ return "Protocol family not supported";
+ case WSAEPROCLIM:
+ return "Too many processes";
+ case WSAEPROTONOSUPPORT:
+ return "Protocol not supported";
+ case WSAEPROTOTYPE:
+ return "Protocol wrong type for socket";
+ case WSAESHUTDOWN:
+ return "Cannot send after socket shutdown";
+ case WSAESOCKTNOSUPPORT:
+ return "Socket type not supported";
+ case WSAETIMEDOUT:
+ return "Connection timed out";
+ case WSAEWOULDBLOCK:
+ return "Resource temporarily unavailable";
+ case WSAHOST_NOT_FOUND:
+ return "Host not found";
+#if 0
+ case WSA_INVALID_HANDLE:
+ return "Specified event object handle is invalid";
+ case WSA_INVALID_PARAMETER:
+ return "One or more parameters are invalid";
+ case WSAINVALIDPROCTABLE:
+ return "Invalid procedure table from service provider";
+ case WSAINVALIDPROVIDER:
+ return "Invalid service provider version number";
+ case WSA_IO_PENDING:
+ return "Overlapped operations will complete later";
+ case WSA_IO_INCOMPLETE:
+ return "Overlapped I/O event object not in signaled state";
+ case WSA_NOT_ENOUGH_MEMORY:
+ return "Insufficient memory available";
+#endif
+ case WSANOTINITIALISED:
+ return "Successful WSAStartup not yet performer";
+ case WSANO_DATA:
+ return "Valid name, no data record of requested type";
+ case WSANO_RECOVERY:
+ return "This is a non-recoverable error";
+#if 0
+ case WSAPROVIDERFAILEDINIT:
+ return "Unable to initialize a service provider";
+ case WSASYSCALLFAILURE:
+ return "System call failure";
+#endif
+ case WSASYSNOTREADY:
+ return "Network subsystem is unavailable";
+ case WSATRY_AGAIN:
+ return "Non-authoritative host not found";
+ case WSAVERNOTSUPPORTED:
+ return "WINSOCK.DLL version out of range";
+ case WSAEDISCON:
+ return "Graceful shutdown in progress";
+#if 0
+ case WSA_OPERATION_ABORTED:
+ return "Overlapped operation aborted";
+#endif
+ }
+ return "Unknown WinSock error";
+}
+#endif /* _WIN32 */
diff --git a/contrib/isc-dhcp/omapip/generic.c b/contrib/isc-dhcp/omapip/generic.c
new file mode 100644
index 000000000000..6154bcf6d7e8
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/generic.c
@@ -0,0 +1,311 @@
+/* generic.c
+
+ Subroutines that support the generic object. */
+
+/*
+ * Copyright (c) 1999-2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+OMAPI_OBJECT_ALLOC (omapi_generic,
+ omapi_generic_object_t, omapi_type_generic)
+
+isc_result_t omapi_generic_new (omapi_object_t **gen,
+ const char *file, int line)
+{
+ /* Backwards compatibility. */
+ return omapi_generic_allocate ((omapi_generic_object_t **)gen,
+ file, line);
+}
+
+isc_result_t omapi_generic_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_generic_object_t *g;
+ omapi_value_t *new;
+ omapi_value_t **va;
+ u_int8_t *ca;
+ int vm_new;
+ int i, vfree = -1;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_generic)
+ return ISC_R_INVALIDARG;
+ g = (omapi_generic_object_t *)h;
+
+ /* See if there's already a value with this name attached to
+ the generic object, and if so, replace the current value
+ with the new one. */
+ for (i = 0; i < g -> nvalues; i++) {
+ if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
+ /* There's an inconsistency here: the standard
+ behaviour of a set_values method when
+ passed a matching name and a null value is
+ to delete the value associated with that
+ name (where possible). In the generic
+ object, we remember the name/null pair,
+ because generic objects are generally used
+ to pass messages around, and this is the
+ way that remote entities delete values from
+ local objects. If the get_value method of
+ a generic object is called for a name that
+ maps to a name/null pair, ISC_R_NOTFOUND is
+ returned. */
+ new = (omapi_value_t *)0;
+ status = (omapi_value_new (&new, MDL));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ omapi_data_string_reference (&new -> name, name, MDL);
+ if (value)
+ omapi_typed_data_reference (&new -> value,
+ value, MDL);
+
+ omapi_value_dereference (&(g -> values [i]), MDL);
+ status = (omapi_value_reference
+ (&(g -> values [i]), new, MDL));
+ omapi_value_dereference (&new, MDL);
+ g -> changed [i] = 1;
+ return status;
+ }
+ /* Notice a free slot if we pass one. */
+ else if (vfree == -1 && !g -> values [i])
+ vfree = i;
+ }
+
+ /* If the name isn't already attached to this object, see if an
+ inner object has it. */
+ if (h -> inner && h -> inner -> type -> set_value) {
+ status = ((*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value));
+ if (status != ISC_R_NOTFOUND)
+ return status;
+ }
+
+ /* Okay, so it's a value that no inner object knows about, and
+ (implicitly, since the outer object set_value method would
+ have called this object's set_value method) it's an object that
+ no outer object knows about, it's this object's responsibility
+ to remember it - that's what generic objects do. */
+
+ /* Arrange for there to be space for the pointer to the new
+ name/value pair if necessary: */
+ if (vfree == -1) {
+ vfree = g -> nvalues;
+ if (vfree == g -> va_max) {
+ if (g -> va_max)
+ vm_new = 2 * g -> va_max;
+ else
+ vm_new = 10;
+ va = dmalloc (vm_new * sizeof *va, MDL);
+ if (!va)
+ return ISC_R_NOMEMORY;
+ ca = dmalloc (vm_new * sizeof *ca, MDL);
+ if (!ca) {
+ dfree (va, MDL);
+ return ISC_R_NOMEMORY;
+ }
+ if (g -> va_max) {
+ memcpy (va, g -> values,
+ g -> va_max * sizeof *va);
+ memcpy (ca, g -> changed,
+ g -> va_max * sizeof *ca);
+ }
+ memset (va + g -> va_max, 0,
+ (vm_new - g -> va_max) * sizeof *va);
+ memset (ca + g -> va_max, 0,
+ (vm_new - g -> va_max) * sizeof *ca);
+ if (g -> values)
+ dfree (g -> values, MDL);
+ if (g -> changed)
+ dfree (g -> changed, MDL);
+ g -> values = va;
+ g -> changed = ca;
+ g -> va_max = vm_new;
+ }
+ }
+ status = omapi_value_new (&g -> values [vfree], MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ omapi_data_string_reference (&g -> values [vfree] -> name,
+ name, MDL);
+ if (value)
+ omapi_typed_data_reference
+ (&g -> values [vfree] -> value, value, MDL);
+ g -> changed [vfree] = 1;
+ if (vfree == g -> nvalues)
+ g -> nvalues++;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_generic_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ int i;
+ omapi_generic_object_t *g;
+
+ if (h -> type != omapi_type_generic)
+ return ISC_R_INVALIDARG;
+ g = (omapi_generic_object_t *)h;
+
+ /* Look up the specified name in our list of objects. */
+ for (i = 0; i < g -> nvalues; i++) {
+ if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
+ /* If this is a name/null value pair, this is the
+ same as if there were no value that matched
+ the specified name, so return ISC_R_NOTFOUND. */
+ if (!g -> values [i] -> value)
+ return ISC_R_NOTFOUND;
+ /* Otherwise, return the name/value pair. */
+ return omapi_value_reference (value,
+ g -> values [i], MDL);
+ }
+ }
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_generic_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_generic_object_t *g;
+ int i;
+
+ if (h -> type != omapi_type_generic)
+ return ISC_R_UNEXPECTED;
+ g = (omapi_generic_object_t *)h;
+
+ if (g -> values) {
+ for (i = 0; i < g -> nvalues; i++) {
+ if (g -> values [i])
+ omapi_value_dereference (&g -> values [i],
+ file, line);
+ }
+ dfree (g -> values, file, line);
+ dfree (g -> changed, file, line);
+ g -> values = (omapi_value_t **)0;
+ g -> changed = (u_int8_t *)0;
+ g -> va_max = 0;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_generic_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != omapi_type_generic)
+ return ISC_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_generic_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *g)
+{
+ omapi_generic_object_t *src;
+ int i;
+ isc_result_t status;
+
+ if (g -> type != omapi_type_generic)
+ return ISC_R_INVALIDARG;
+ src = (omapi_generic_object_t *)g;
+
+ for (i = 0; i < src -> nvalues; i++) {
+ if (src -> values [i] && src -> values [i] -> name -> len &&
+ src -> changed [i]) {
+ status = (omapi_connection_put_uint16
+ (c, src -> values [i] -> name -> len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_copyin
+ (c, src -> values [i] -> name -> value,
+ src -> values [i] -> name -> len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = (omapi_connection_write_typed_data
+ (c, src -> values [i] -> value));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ }
+
+ if (g -> inner && g -> inner -> type -> stuff_values)
+ return (*(g -> inner -> type -> stuff_values)) (c, id,
+ g -> inner);
+ return ISC_R_SUCCESS;
+}
+
+/* Clear the changed flags on the object. This has the effect that if
+ generic_stuff is called, any attributes that still have a cleared changed
+ flag aren't sent to the peer. This also deletes any values that are
+ null, presuming that these have now been properly handled. */
+
+isc_result_t omapi_generic_clear_flags (omapi_object_t *o)
+{
+ int i;
+ isc_result_t status;
+ omapi_generic_object_t *g;
+
+ if (o -> type != omapi_type_generic)
+ return ISC_R_INVALIDARG;
+ g = (omapi_generic_object_t *)o;
+
+ for (i = 0; i < g -> nvalues; i++) {
+ g -> changed [i] = 0;
+ if (g -> values [i] &&
+ !g -> values [i] -> value)
+ omapi_value_dereference (&g -> values [i], MDL);
+ }
+ return ISC_R_SUCCESS;
+}
diff --git a/contrib/isc-dhcp/omapip/handle.c b/contrib/isc-dhcp/omapip/handle.c
new file mode 100644
index 000000000000..3b99ec7c3519
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/handle.c
@@ -0,0 +1,304 @@
+/* handle.c
+
+ Functions for maintaining handles on objects. */
+
+/*
+ * Copyright (c) 1999-2000 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+/* The handle table is a hierarchical tree designed for quick mapping
+ of handle identifiers to objects. Objects contain their own handle
+ identifiers if they have them, so the reverse mapping is also
+ quick. The hierarchy is made up of table objects, each of which
+ has 120 entries, a flag indicating whether the table is a leaf
+ table or an indirect table, the handle of the first object covered
+ by the table and the first object after that that's *not* covered
+ by the table, a count of how many objects of either type are
+ currently stored in the table, and an array of 120 entries pointing
+ either to objects or tables.
+
+ When we go to add an object to the table, we look to see if the
+ next object handle to be assigned is covered by the outermost
+ table. If it is, we find the place within that table where the
+ next handle should go, and if necessary create additional nodes in
+ the tree to contain the new handle. The pointer to the object is
+ then stored in the correct position.
+
+ Theoretically, we could have some code here to free up handle
+ tables as they go out of use, but by and large handle tables won't
+ go out of use, so this is being skipped for now. It shouldn't be
+ too hard to implement in the future if there's a different
+ application. */
+
+omapi_handle_table_t *omapi_handle_table;
+omapi_handle_t omapi_next_handle = 1; /* Next handle to be assigned. */
+
+static isc_result_t omapi_handle_lookup_in (omapi_object_t **,
+ omapi_handle_t,
+ omapi_handle_table_t *);
+static isc_result_t omapi_object_handle_in_table (omapi_handle_t,
+ omapi_handle_table_t *,
+ omapi_object_t *);
+static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **);
+
+isc_result_t omapi_object_handle (omapi_handle_t *h, omapi_object_t *o)
+{
+ int tabix;
+ isc_result_t status;
+
+ if (o -> handle) {
+ *h = o -> handle;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!omapi_handle_table) {
+ omapi_handle_table = dmalloc (sizeof *omapi_handle_table, MDL);
+ if (!omapi_handle_table)
+ return ISC_R_NOMEMORY;
+ memset (omapi_handle_table, 0, sizeof *omapi_handle_table);
+ omapi_handle_table -> first = 0;
+ omapi_handle_table -> limit = OMAPI_HANDLE_TABLE_SIZE;
+ omapi_handle_table -> leafp = 1;
+ }
+
+ /* If this handle doesn't fit in the outer table, we need to
+ make a new outer table. This is a while loop in case for
+ some reason we decide to do disjoint handle allocation,
+ where the next level of indirection still isn't big enough
+ to enclose the next handle ID. */
+
+ while (omapi_next_handle >= omapi_handle_table -> limit) {
+ omapi_handle_table_t *new;
+
+ new = dmalloc (sizeof *new, MDL);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, sizeof *new);
+ new -> first = 0;
+ new -> limit = (omapi_handle_table -> limit *
+ OMAPI_HANDLE_TABLE_SIZE);
+ new -> leafp = 0;
+ new -> children [0].table = omapi_handle_table;
+ omapi_handle_table = new;
+ }
+
+ /* Try to cram this handle into the existing table. */
+ status = omapi_object_handle_in_table (omapi_next_handle,
+ omapi_handle_table, o);
+ /* If it worked, return the next handle and increment it. */
+ if (status == ISC_R_SUCCESS) {
+ *h = omapi_next_handle;
+ omapi_next_handle++;
+ return ISC_R_SUCCESS;
+ }
+ if (status != ISC_R_NOSPACE)
+ return status;
+
+ status = omapi_handle_table_enclose (&omapi_handle_table);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_handle_in_table (omapi_next_handle,
+ omapi_handle_table, o);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ *h = omapi_next_handle;
+ omapi_next_handle++;
+
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t omapi_object_handle_in_table (omapi_handle_t h,
+ omapi_handle_table_t *table,
+ omapi_object_t *o)
+{
+ omapi_handle_table_t *inner;
+ omapi_handle_t scale, index;
+ isc_result_t status;
+
+ if (table -> first > h || table -> limit <= h)
+ return ISC_R_NOSPACE;
+
+ /* If this is a leaf table, just stash the object in the
+ appropriate place. */
+ if (table -> leafp) {
+ status = (omapi_object_reference
+ (&table -> children [h - table -> first].object,
+ o, MDL));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ o -> handle = h;
+ return ISC_R_SUCCESS;
+ }
+
+ /* Scale is the number of handles represented by each child of this
+ table. For a leaf table, scale would be 1. For a first level
+ of indirection, 120. For a second, 120 * 120. Et cetera. */
+ scale = (table -> limit - table -> first) / OMAPI_HANDLE_TABLE_SIZE;
+
+ /* So the next most direct table from this one that contains the
+ handle must be the subtable of this table whose index into this
+ table's array of children is the handle divided by the scale. */
+ index = (h - table -> first) / scale;
+ inner = table -> children [index].table;
+
+ /* If there is no more direct table than this one in the slot
+ we came up with, make one. */
+ if (!inner) {
+ inner = dmalloc (sizeof *inner, MDL);
+ if (!inner)
+ return ISC_R_NOMEMORY;
+ memset (inner, 0, sizeof *inner);
+ inner -> first = index * scale + table -> first;
+ inner -> limit = inner -> first + scale;
+ if (scale == OMAPI_HANDLE_TABLE_SIZE)
+ inner -> leafp = 1;
+ table -> children [index].table = inner;
+ }
+
+ status = omapi_object_handle_in_table (h, inner, o);
+ if (status == ISC_R_NOSPACE) {
+ status = (omapi_handle_table_enclose
+ (&table -> children [index].table));
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ return omapi_object_handle_in_table
+ (h, table -> children [index].table, o);
+ }
+ return status;
+}
+
+static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **table)
+{
+ omapi_handle_table_t *inner = *table;
+ omapi_handle_table_t *new;
+ int index, base, scale;
+
+ /* The scale of the table we're enclosing is going to be the
+ difference between its "first" and "limit" members. So the
+ scale of the table enclosing it is going to be that multiplied
+ by the table size. */
+ scale = (inner -> first - inner -> limit) * OMAPI_HANDLE_TABLE_SIZE;
+
+ /* The range that the enclosing table covers is going to be
+ the result of subtracting the remainder of dividing the
+ enclosed table's first entry number by the enclosing
+ table's scale. If handle IDs are being allocated
+ sequentially, the enclosing table's "first" value will be
+ the same as the enclosed table's "first" value. */
+ base = inner -> first - inner -> first % scale;
+
+ /* The index into the enclosing table at which the enclosed table
+ will be stored is going to be the difference between the "first"
+ value of the enclosing table and the enclosed table - zero, if
+ we are allocating sequentially. */
+ index = (base - inner -> first) / OMAPI_HANDLE_TABLE_SIZE;
+
+ new = dmalloc (sizeof *new, MDL);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, sizeof *new);
+ new -> first = base;
+ new -> limit = base + scale;
+ if (scale == OMAPI_HANDLE_TABLE_SIZE)
+ new -> leafp = 0;
+ new -> children [index].table = inner;
+ *table = new;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_handle_lookup (omapi_object_t **o, omapi_handle_t h)
+{
+ return omapi_handle_lookup_in (o, h, omapi_handle_table);
+}
+
+static isc_result_t omapi_handle_lookup_in (omapi_object_t **o,
+ omapi_handle_t h,
+ omapi_handle_table_t *table)
+
+{
+ omapi_handle_table_t *inner;
+ omapi_handle_t scale, index;
+
+ if (!table || table -> first > h || table -> limit <= h)
+ return ISC_R_NOTFOUND;
+
+ /* If this is a leaf table, just grab the object. */
+ if (table -> leafp) {
+ /* Not there? */
+ if (!table -> children [h - table -> first].object)
+ return ISC_R_NOTFOUND;
+ return omapi_object_reference
+ (o, table -> children [h - table -> first].object,
+ MDL);
+ }
+
+ /* Scale is the number of handles represented by each child of this
+ table. For a leaf table, scale would be 1. For a first level
+ of indirection, 120. For a second, 120 * 120. Et cetera. */
+ scale = (table -> limit - table -> first) / OMAPI_HANDLE_TABLE_SIZE;
+
+ /* So the next most direct table from this one that contains the
+ handle must be the subtable of this table whose index into this
+ table's array of children is the handle divided by the scale. */
+ index = (h - table -> first) / scale;
+ inner = table -> children [index].table;
+
+ return omapi_handle_lookup_in (o, h, table -> children [index].table);
+}
+
+/* For looking up objects based on handles that have been sent on the wire. */
+isc_result_t omapi_handle_td_lookup (omapi_object_t **obj,
+ omapi_typed_data_t *handle)
+{
+ isc_result_t status;
+ omapi_handle_t h;
+
+ if (handle -> type == omapi_datatype_int)
+ h = handle -> u.integer;
+ else if (handle -> type == omapi_datatype_data &&
+ handle -> u.buffer.len == sizeof h) {
+ memcpy (&h, handle -> u.buffer.value, sizeof h);
+ h = ntohl (h);
+ } else
+ return ISC_R_INVALIDARG;
+ return omapi_handle_lookup (obj, h);
+}
diff --git a/contrib/isc-dhcp/omapip/hash.c b/contrib/isc-dhcp/omapip/hash.c
new file mode 100644
index 000000000000..67c46bfc627d
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/hash.c
@@ -0,0 +1,425 @@
+/* hash.c
+
+ Routines for manipulating hash tables... */
+
+/*
+ * Copyright (c) 1995-2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: hash.c,v 1.1.2.5 2001/10/17 04:00:35 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include <omapip/omapip_p.h>
+#include <ctype.h>
+
+static int do_hash (const unsigned char *, unsigned, unsigned);
+static int do_case_hash (const unsigned char *, unsigned, unsigned);
+
+int new_hash_table (tp, count, file, line)
+ struct hash_table **tp;
+ int count;
+ const char *file;
+ int line;
+{
+ struct hash_table *rval;
+
+ if (!tp) {
+ log_error ("%s(%d): new_hash_table called with null pointer.",
+ file, line);
+#if defined (POINTER_DEBUG)
+ abort ();
+#endif
+ return 0;
+ }
+ if (*tp) {
+ log_error ("%s(%d): non-null target for new_hash_table.",
+ file, line);
+#if defined (POINTER_DEBUG)
+ abort ();
+#endif
+ }
+ rval = dmalloc (sizeof (struct hash_table) -
+ (DEFAULT_HASH_SIZE * sizeof (struct hash_bucket *)) +
+ (count * sizeof (struct hash_bucket *)), file, line);
+ if (!rval)
+ return 0;
+ rval -> hash_count = count;
+ *tp = rval;
+ return 1;
+}
+
+void free_hash_table (tp, file, line)
+ struct hash_table **tp;
+ const char *file;
+ int line;
+{
+ int i;
+ struct hash_bucket *hbc, *hbn = (struct hash_bucket *)0;
+ struct hash_table *ptr = *tp;
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ for (i = 0; i < ptr -> hash_count; i++) {
+ for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) {
+ hbn = hbc -> next;
+ if (ptr -> dereferencer && hbc -> value)
+ (*ptr -> dereferencer) (&hbc -> value, MDL);
+ }
+ for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) {
+ hbn = hbc -> next;
+ free_hash_bucket (hbc, MDL);
+ }
+ ptr -> buckets [i] = (struct hash_bucket *)0;
+ }
+#endif
+
+ dfree ((VOIDPTR)ptr, MDL);
+ *tp = (struct hash_table *)0;
+}
+
+struct hash_bucket *free_hash_buckets;
+
+#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+struct hash_bucket *hash_bucket_hunks;
+
+void relinquish_hash_bucket_hunks ()
+{
+ struct hash_bucket *c, *n, **p;
+
+ /* Account for all the hash buckets on the free list. */
+ p = &free_hash_buckets;
+ for (c = free_hash_buckets; c; c = c -> next) {
+ for (n = hash_bucket_hunks; n; n = n -> next) {
+ if (c > n && c < n + 127) {
+ *p = c -> next;
+ n -> len++;
+ break;
+ }
+ }
+ /* If we didn't delete the hash bucket from the free list,
+ advance the pointer. */
+ if (!n)
+ p = &c -> next;
+ }
+
+ for (c = hash_bucket_hunks; c; c = n) {
+ n = c -> next;
+ if (c -> len != 126) {
+ log_info ("hashbucket %lx hash_buckets %d free %u",
+ (unsigned long)c, 127, c -> len);
+ }
+ dfree (c, MDL);
+ }
+}
+#endif
+
+struct hash_bucket *new_hash_bucket (file, line)
+ const char *file;
+ int line;
+{
+ struct hash_bucket *rval;
+ int i = 0;
+ if (!free_hash_buckets) {
+ rval = dmalloc (127 * sizeof (struct hash_bucket),
+ file, line);
+ if (!rval)
+ return rval;
+# if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ rval -> next = hash_bucket_hunks;
+ hash_bucket_hunks = rval;
+ hash_bucket_hunks -> len = 0;
+ i++;
+ rval++;
+#endif
+ for (; i < 127; i++) {
+ rval -> next = free_hash_buckets;
+ free_hash_buckets = rval;
+ rval++;
+ }
+ }
+ rval = free_hash_buckets;
+ free_hash_buckets = rval -> next;
+ return rval;
+}
+
+void free_hash_bucket (ptr, file, line)
+ struct hash_bucket *ptr;
+ const char *file;
+ int line;
+{
+ struct hash_bucket *hp;
+#if defined (DEBUG_MALLOC_POOL)
+ for (hp = free_hash_buckets; hp; hp = hp -> next) {
+ if (hp == ptr) {
+ log_error ("hash bucket freed twice!");
+ abort ();
+ }
+ }
+#endif
+ ptr -> next = free_hash_buckets;
+ free_hash_buckets = ptr;
+}
+
+int new_hash (struct hash_table **rp,
+ hash_reference referencer,
+ hash_dereference dereferencer,
+ int casep, const char *file, int line)
+{
+ if (!new_hash_table (rp, DEFAULT_HASH_SIZE, file, line))
+ return 0;
+ memset (&(*rp) -> buckets [0], 0,
+ DEFAULT_HASH_SIZE * sizeof (struct hash_bucket *));
+ (*rp) -> referencer = referencer;
+ (*rp) -> dereferencer = dereferencer;
+ if (casep) {
+ (*rp) -> cmp = casecmp;
+ (*rp) -> do_hash = do_case_hash;
+ } else {
+ (*rp) -> cmp = (hash_comparator_t)memcmp;
+ (*rp) -> do_hash = do_hash;
+ }
+ return 1;
+}
+
+static int do_case_hash (name, len, size)
+ const unsigned char *name;
+ unsigned len;
+ unsigned size;
+{
+ register int accum = 0;
+ register const unsigned char *s = (const unsigned char *)name;
+ int i = len;
+ register unsigned c;
+
+ while (i--) {
+ /* Make the hash case-insensitive. */
+ c = *s++;
+ if (isascii (c) && isupper (c))
+ c = tolower (c);
+
+ /* Add the character in... */
+ accum = (accum << 1) + c;
+
+ /* Add carry back in... */
+ while (accum > 65535) {
+ accum = (accum & 65535) + (accum >> 16);
+ }
+ }
+ return accum % size;
+}
+
+static int do_hash (name, len, size)
+ const unsigned char *name;
+ unsigned len;
+ unsigned size;
+{
+ register int accum = 0;
+ register const unsigned char *s = (const unsigned char *)name;
+ int i = len;
+
+ while (i--) {
+ /* Add the character in... */
+ accum = (accum << 1) + *s++;
+
+ /* Add carry back in... */
+ while (accum > 65535) {
+ accum = (accum & 65535) + (accum >> 16);
+ }
+ }
+ return accum % size;
+}
+
+void add_hash (table, name, len, pointer, file, line)
+ struct hash_table *table;
+ unsigned len;
+ const unsigned char *name;
+ hashed_object_t *pointer;
+ const char *file;
+ int line;
+{
+ int hashno;
+ struct hash_bucket *bp;
+ void *foo;
+
+ if (!table)
+ return;
+
+ if (!len)
+ len = strlen ((const char *)name);
+
+ hashno = (*table -> do_hash) (name, len, table -> hash_count);
+ bp = new_hash_bucket (file, line);
+
+ if (!bp) {
+ log_error ("Can't add %s to hash table.", name);
+ return;
+ }
+ bp -> name = name;
+ if (table -> referencer) {
+ foo = &bp -> value;
+ (*(table -> referencer)) (foo, pointer, file, line);
+ } else
+ bp -> value = pointer;
+ bp -> next = table -> buckets [hashno];
+ bp -> len = len;
+ table -> buckets [hashno] = bp;
+}
+
+void delete_hash_entry (table, name, len, file, line)
+ struct hash_table *table;
+ unsigned len;
+ const unsigned char *name;
+ const char *file;
+ int line;
+{
+ int hashno;
+ struct hash_bucket *bp, *pbp = (struct hash_bucket *)0;
+ void *foo;
+
+ if (!table)
+ return;
+
+ if (!len)
+ len = strlen ((const char *)name);
+
+ hashno = (*table -> do_hash) (name, len, table -> hash_count);
+
+ /* Go through the list looking for an entry that matches;
+ if we find it, delete it. */
+ for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
+ if ((!bp -> len &&
+ !strcmp ((const char *)bp -> name, (const char *)name)) ||
+ (bp -> len == len &&
+ !(*table -> cmp) (bp -> name, name, len))) {
+ if (pbp) {
+ pbp -> next = bp -> next;
+ } else {
+ table -> buckets [hashno] = bp -> next;
+ }
+ if (bp -> value && table -> dereferencer) {
+ foo = &bp -> value;
+ (*(table -> dereferencer)) (foo, file, line);
+ }
+ free_hash_bucket (bp, file, line);
+ break;
+ }
+ pbp = bp; /* jwg, 9/6/96 - nice catch! */
+ }
+}
+
+int hash_lookup (vp, table, name, len, file, line)
+ hashed_object_t **vp;
+ struct hash_table *table;
+ const unsigned char *name;
+ unsigned len;
+ const char *file;
+ int line;
+{
+ int hashno;
+ struct hash_bucket *bp;
+
+ if (!table)
+ return 0;
+ if (!len)
+ len = strlen ((const char *)name);
+
+ hashno = (*table -> do_hash) (name, len, table -> hash_count);
+
+ for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
+ if (len == bp -> len
+ && !(*table -> cmp) (bp -> name, name, len)) {
+ if (table -> referencer)
+ (*table -> referencer) (vp, bp -> value,
+ file, line);
+ else
+ *vp = bp -> value;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int hash_foreach (struct hash_table *table, hash_foreach_func func)
+{
+ int i;
+ struct hash_bucket *bp, *next;
+ int count = 0;
+
+ if (!table)
+ return 0;
+
+ for (i = 0; i < table -> hash_count; i++) {
+ bp = table -> buckets [i];
+ while (bp) {
+ next = bp -> next;
+ (*func) (bp -> name, bp -> len, bp -> value);
+ bp = next;
+ count++;
+ }
+ }
+ return count;
+}
+
+int casecmp (const void *v1, const void *v2, unsigned long len)
+{
+ unsigned i;
+ const char *s = v1;
+ const char *t = v2;
+
+ for (i = 0; i < len; i++)
+ {
+ int c1, c2;
+ if (isascii (s [i]) && isupper (s [i]))
+ c1 = tolower (s [i]);
+ else
+ c1 = s [i];
+
+ if (isascii (t [i]) && isupper (t [i]))
+ c2 = tolower (t [i]);
+ else
+ c2 = t [i];
+
+ if (c1 < c2)
+ return -1;
+ if (c1 > c2)
+ return 1;
+ }
+ return 0;
+}
diff --git a/contrib/isc-dhcp/omapip/inet_addr.c b/contrib/isc-dhcp/omapip/inet_addr.c
new file mode 100644
index 000000000000..0e7967cd2794
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/inet_addr.c
@@ -0,0 +1,150 @@
+/* $NetBSD: inet_addr.c,v 1.6 1996/02/02 15:22:23 mrg Exp $ */
+
+/*
+ * Copyright (c) 1983, 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
+#else
+static char rcsid[] = "$NetBSD: inet_addr.c,v 1.6 1996/02/02 15:22:23 mrg Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef lint
+static char copyright[] =
+"$Id: inet_addr.c,v 1.1 2000/09/20 00:01:50 mellon Exp $ Copyright (c) 1983, 1990, 1993 The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include "omapip/omapip_p.h"
+
+#ifdef NEED_INET_ATON
+/*
+ * 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.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+inet_aton(cp, addr)
+ const char *cp;
+ struct in_addr *addr;
+{
+ register u_long val;
+ register int base, n;
+ register char c;
+ u_int parts[4];
+ register u_int *pp = parts;
+
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, other=decimal.
+ */
+ val = 0; base = 10;
+ if (*cp == '0') {
+ if (*++cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ else
+ base = 8;
+ }
+ while ((c = *cp) != '\0') {
+ if (isascii(c) && isdigit(c)) {
+ val = (val * base) + (c - '0');
+ cp++;
+ continue;
+ }
+ if (base == 16 && isascii(c) && isxdigit(c)) {
+ val = (val << 4) +
+ (c + 10 - (islower(c) ? 'a' : 'A'));
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (*cp == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16-bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xff)
+ return (0);
+ *pp++ = val, cp++;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (*cp && (!isascii(*cp) || !isspace(*cp)))
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+
+ case 0:
+ return (0); /* initial nondigit */
+
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr)
+ addr->s_addr = htonl(val);
+ return (1);
+}
+#endif
diff --git a/contrib/isc-dhcp/omapip/listener.c b/contrib/isc-dhcp/omapip/listener.c
new file mode 100644
index 000000000000..9953a9120744
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/listener.c
@@ -0,0 +1,477 @@
+/* listener.c
+
+ Subroutines that support the generic listener object. */
+
+/*
+ * Copyright (c) 1999-2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+#if defined (TRACING)
+omapi_array_t *trace_listeners;
+static void trace_listener_accept_input (trace_type_t *, unsigned, char *);
+static void trace_listener_remember (omapi_listener_object_t *,
+ const char *, int);
+static void trace_listener_accept_stop (trace_type_t *);
+trace_type_t *trace_listener_accept;
+#endif
+
+OMAPI_OBJECT_ALLOC (omapi_listener,
+ omapi_listener_object_t, omapi_type_listener)
+
+isc_result_t omapi_listen (omapi_object_t *h,
+ unsigned port,
+ int max)
+{
+ omapi_addr_t addr;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_listen(port=%d, max=%d)", port, max);
+#endif
+
+ addr.addrtype = AF_INET;
+ addr.addrlen = sizeof (struct in_addr);
+ memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */
+ addr.port = port;
+
+ return omapi_listen_addr (h, &addr, max);
+}
+
+isc_result_t omapi_listen_addr (omapi_object_t *h,
+ omapi_addr_t *addr,
+ int max)
+{
+ struct hostent *he;
+ int hix;
+ isc_result_t status;
+ omapi_listener_object_t *obj;
+ int i;
+ struct in_addr ia;
+
+ /* Get the handle. */
+ obj = (omapi_listener_object_t *)0;
+ status = omapi_listener_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ /* Connect this object to the inner object. */
+ status = omapi_object_reference (&h -> outer,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_listener_dereference (&obj, MDL);
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, h, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_listener_dereference (&obj, MDL);
+ return status;
+ }
+
+ /* Currently only support TCPv4 addresses. */
+ if (addr -> addrtype != AF_INET)
+ return ISC_R_INVALIDARG;
+
+ /* Set up the address on which we will listen... */
+ obj -> address.sin_port = htons (addr -> port);
+ memcpy (&obj -> address.sin_addr,
+ addr -> address, sizeof obj -> address.sin_addr);
+#if defined (HAVE_SA_LEN)
+ obj -> address.sin_len =
+ sizeof (struct sockaddr_in);
+#endif
+ obj -> address.sin_family = AF_INET;
+ memset (&(obj -> address.sin_zero), 0,
+ sizeof obj -> address.sin_zero);
+
+#if defined (TRACING)
+ /* If we're playing back a trace file, we remember the object
+ on the trace listener queue. */
+ if (trace_playback ()) {
+ trace_listener_remember (obj, MDL);
+ } else {
+#endif
+ /* Create a socket on which to listen. */
+ obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (!obj -> socket) {
+ omapi_listener_dereference (&obj, MDL);
+ if (errno == EMFILE
+ || errno == ENFILE || errno == ENOBUFS)
+ return ISC_R_NORESOURCES;
+ return ISC_R_UNEXPECTED;
+ }
+
+#if defined (HAVE_SETFD)
+ if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
+ close (obj -> socket);
+ omapi_listener_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+#endif
+
+ /* Set the REUSEADDR option so that we don't fail to start if
+ we're being restarted. */
+ i = 1;
+ if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&i, sizeof i) < 0) {
+ close (obj -> socket);
+ omapi_listener_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Try to bind to the wildcard address using the port number
+ we were given. */
+ i = bind (obj -> socket,
+ (struct sockaddr *)&obj -> address,
+ sizeof obj -> address);
+ if (i < 0) {
+ omapi_listener_dereference (&obj, MDL);
+ if (errno == EADDRINUSE)
+ return ISC_R_ADDRNOTAVAIL;
+ if (errno == EPERM)
+ return ISC_R_NOPERM;
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Now tell the kernel to listen for connections. */
+ if (listen (obj -> socket, max)) {
+ omapi_listener_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+
+ if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
+ omapi_listener_dereference (&obj, MDL);
+ return ISC_R_UNEXPECTED;
+ }
+
+ status = omapi_register_io_object ((omapi_object_t *)obj,
+ omapi_listener_readfd, 0,
+ omapi_accept, 0, 0);
+#if defined (TRACING)
+ }
+#endif
+ omapi_listener_dereference (&obj, MDL);
+ return status;
+}
+
+/* Return the socket on which the dispatcher should wait for readiness
+ to read, for a listener object. */
+int omapi_listener_readfd (omapi_object_t *h)
+{
+ omapi_listener_object_t *l;
+
+ if (h -> type != omapi_type_listener)
+ return -1;
+ l = (omapi_listener_object_t *)h;
+
+ return l -> socket;
+}
+
+/* Reader callback for a listener object. Accept an incoming connection. */
+isc_result_t omapi_accept (omapi_object_t *h)
+{
+ isc_result_t status;
+ SOCKLEN_T len;
+ omapi_connection_object_t *obj;
+ omapi_listener_object_t *listener;
+ omapi_addr_t remote_addr;
+ int i;
+ struct sockaddr_in addr;
+ int socket;
+
+ if (h -> type != omapi_type_listener)
+ return ISC_R_INVALIDARG;
+ listener = (omapi_listener_object_t *)h;
+
+ /* Accept the connection. */
+ len = sizeof addr;
+ socket = accept (listener -> socket,
+ ((struct sockaddr *)&(addr)), &len);
+ if (socket < 0) {
+ if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
+ return ISC_R_NORESOURCES;
+ return ISC_R_UNEXPECTED;
+ }
+
+#if defined (TRACING)
+ /* If we're recording a trace, remember the connection. */
+ if (trace_record ()) {
+ trace_iov_t iov [3];
+ u_int32_t lsock;
+ iov [0].buf = (char *)&addr.sin_port;
+ iov [0].len = sizeof addr.sin_port;
+ iov [1].buf = (char *)&addr.sin_addr;
+ iov [1].len = sizeof addr.sin_addr;
+ iov [2].buf = (char *)&listener -> address.sin_port;
+ iov [2].len = sizeof listener -> address.sin_port;
+ trace_write_packet_iov (trace_listener_accept,
+ 3, iov, MDL);
+ }
+#endif
+
+ obj = (omapi_connection_object_t *)0;
+ status = omapi_listener_connect (&obj, listener, socket, &addr);
+ if (status != ISC_R_SUCCESS) {
+ close (socket);
+ return status;
+ }
+
+ status = omapi_register_io_object ((omapi_object_t *)obj,
+ omapi_connection_readfd,
+ omapi_connection_writefd,
+ omapi_connection_reader,
+ omapi_connection_writer,
+ omapi_connection_reaper);
+
+ /* Lose our reference to the connection, so it'll be gc'd when it's
+ reaped. */
+ omapi_connection_dereference (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ omapi_disconnect ((omapi_object_t *)(obj), 1);
+ return status;
+}
+
+isc_result_t omapi_listener_connect (omapi_connection_object_t **obj,
+ omapi_listener_object_t *listener,
+ int socket,
+ struct sockaddr_in *remote_addr)
+{
+ isc_result_t status;
+ omapi_object_t *h = (omapi_object_t *)listener;
+ omapi_addr_t addr;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_accept()");
+#endif
+
+ /* Get the handle. */
+ status = omapi_connection_allocate (obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ (*obj) -> state = omapi_connection_connected;
+ (*obj) -> remote_addr = *remote_addr;
+ (*obj) -> socket = socket;
+
+ /* Verify that this host is allowed to connect. */
+ if (listener -> verify_addr) {
+ addr.addrtype = AF_INET;
+ addr.addrlen = sizeof (remote_addr -> sin_addr);
+ memcpy (addr.address, &remote_addr -> sin_addr,
+ sizeof (remote_addr -> sin_addr));
+ addr.port = ntohs(remote_addr -> sin_port);
+
+ status = (listener -> verify_addr) (h, &addr);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect ((omapi_object_t *)(*obj), 1);
+ omapi_connection_dereference (obj, MDL);
+ return status;
+ }
+ }
+
+ omapi_listener_reference (&(*obj) -> listener, listener, MDL);
+#if defined (TRACING)
+ omapi_connection_register (*obj, MDL);
+#endif
+ status = omapi_signal (h, "connect", (*obj));
+ return status;
+}
+
+#if defined (TRACING)
+OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t)
+
+void omapi_listener_trace_setup (void) {
+ trace_listener_accept =
+ trace_type_register ("listener-accept", (void *)0,
+ trace_listener_accept_input,
+ trace_listener_accept_stop, MDL);
+}
+
+static void trace_listener_remember (omapi_listener_object_t *obj,
+ const char *file, int line)
+{
+ isc_result_t status;
+ if (!trace_listeners) {
+ status = omapi_listener_array_allocate (&trace_listeners,
+ file, line);
+ if (status != ISC_R_SUCCESS) {
+ foo:
+ log_error ("trace_listener_remember: %s",
+ isc_result_totext (status));
+ return;
+ }
+ }
+ status = omapi_listener_array_extend (trace_listeners, obj,
+ &obj -> index, MDL);
+ if (status != ISC_R_SUCCESS)
+ goto foo;
+}
+
+static void trace_listener_accept_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ struct in_addr *addr;
+ u_int16_t *remote_port;
+ u_int16_t *local_port;
+ omapi_connection_object_t *obj;
+ isc_result_t status;
+ struct sockaddr_in remote_addr;
+
+ addr = (struct in_addr *)buf;
+ remote_port = (u_int16_t *)(addr + 1);
+ local_port = remote_port + 1;
+
+ memset (&remote_addr, 0, sizeof remote_addr);
+ remote_addr.sin_addr = *addr;
+ remote_addr.sin_port = *remote_port;
+
+ omapi_array_foreach_begin (trace_listeners,
+ omapi_listener_object_t, lp) {
+ if (lp -> address.sin_port == *local_port) {
+ obj = (omapi_connection_object_t *)0;
+ status = omapi_listener_connect (&obj,
+ lp, 0, &remote_addr);
+ omapi_listener_dereference (&lp, MDL);
+ return;
+ }
+ } omapi_array_foreach_end (trace_listeners,
+ omapi_listener_object_t, lp);
+ log_error ("trace_listener_accept: %s from %s/%d to port %d",
+ "unexpected connect",
+ inet_ntoa (*addr), *remote_port, *local_port);
+}
+
+static void trace_listener_accept_stop (trace_type_t *ttype) { }
+
+
+#endif
+
+isc_result_t omapi_listener_configure_security (omapi_object_t *h,
+ isc_result_t (*verify_addr)
+ (omapi_object_t *,
+ omapi_addr_t *))
+{
+ omapi_listener_object_t *l;
+
+ if (h -> type != omapi_type_listener)
+ return ISC_R_INVALIDARG;
+ l = (omapi_listener_object_t *)h;
+
+ l -> verify_addr = verify_addr;
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_listener_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ if (h -> type != omapi_type_listener)
+ return ISC_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_listener_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ if (h -> type != omapi_type_listener)
+ return ISC_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_listener_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_listener_object_t *l;
+
+ if (h -> type != omapi_type_listener)
+ return ISC_R_INVALIDARG;
+ l = (omapi_listener_object_t *)h;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_listener_destroy()");
+#endif
+
+ if (l -> socket != -1) {
+ close (l -> socket);
+ l -> socket = -1;
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_listener_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != omapi_type_listener)
+ return ISC_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_listener_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *l)
+{
+ int i;
+
+ if (l -> type != omapi_type_listener)
+ return ISC_R_INVALIDARG;
+
+ if (l -> inner && l -> inner -> type -> stuff_values)
+ return (*(l -> inner -> type -> stuff_values)) (c, id,
+ l -> inner);
+ return ISC_R_SUCCESS;
+}
+
diff --git a/contrib/isc-dhcp/omapip/message.c b/contrib/isc-dhcp/omapip/message.c
new file mode 100644
index 000000000000..ffdae854fee3
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/message.c
@@ -0,0 +1,769 @@
+/* message.c
+
+ Subroutines for dealing with message objects. */
+
+/*
+ * Copyright (c) 1999-2000 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+OMAPI_OBJECT_ALLOC (omapi_message,
+ omapi_message_object_t, omapi_type_message)
+
+omapi_message_object_t *omapi_registered_messages;
+
+isc_result_t omapi_message_new (omapi_object_t **o, const char *file, int line)
+{
+ omapi_message_object_t *m;
+ omapi_object_t *g;
+ isc_result_t status;
+
+ m = (omapi_message_object_t *)0;
+ status = omapi_message_allocate (&m, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ g = (omapi_object_t *)0;
+ status = omapi_generic_new (&g, file, line);
+ if (status != ISC_R_SUCCESS) {
+ dfree (m, file, line);
+ return status;
+ }
+ status = omapi_object_reference (&m -> inner, g, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&m, file, line);
+ omapi_object_dereference (&g, file, line);
+ return status;
+ }
+ status = omapi_object_reference (&g -> outer,
+ (omapi_object_t *)m, file, line);
+
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&m, file, line);
+ omapi_object_dereference (&g, file, line);
+ return status;
+ }
+
+ status = omapi_object_reference (o, (omapi_object_t *)m, file, line);
+ omapi_message_dereference (&m, file, line);
+ omapi_object_dereference (&g, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ return status;
+}
+
+isc_result_t omapi_message_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_message_object_t *m;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ m = (omapi_message_object_t *)h;
+
+ /* Can't set authlen. */
+
+ /* Can set authenticator, but the value must be typed data. */
+ if (!omapi_ds_strcmp (name, "authenticator")) {
+ if (m -> authenticator)
+ omapi_typed_data_dereference (&m -> authenticator,
+ MDL);
+ omapi_typed_data_reference (&m -> authenticator, value, MDL);
+ return ISC_R_SUCCESS;
+
+ } else if (!omapi_ds_strcmp (name, "object")) {
+ if (value -> type != omapi_datatype_object)
+ return ISC_R_INVALIDARG;
+ if (m -> object)
+ omapi_object_dereference (&m -> object, MDL);
+ omapi_object_reference (&m -> object, value -> u.object, MDL);
+ return ISC_R_SUCCESS;
+
+ } else if (!omapi_ds_strcmp (name, "notify-object")) {
+ if (value -> type != omapi_datatype_object)
+ return ISC_R_INVALIDARG;
+ if (m -> notify_object)
+ omapi_object_dereference (&m -> notify_object, MDL);
+ omapi_object_reference (&m -> notify_object,
+ value -> u.object, MDL);
+ return ISC_R_SUCCESS;
+
+ /* Can set authid, but it has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "authid")) {
+ if (value -> type != omapi_datatype_int)
+ return ISC_R_INVALIDARG;
+ m -> authid = value -> u.integer;
+ return ISC_R_SUCCESS;
+
+ /* Can set op, but it has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "op")) {
+ if (value -> type != omapi_datatype_int)
+ return ISC_R_INVALIDARG;
+ m -> op = value -> u.integer;
+ return ISC_R_SUCCESS;
+
+ /* Handle also has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "handle")) {
+ if (value -> type != omapi_datatype_int)
+ return ISC_R_INVALIDARG;
+ m -> h = value -> u.integer;
+ return ISC_R_SUCCESS;
+
+ /* Transaction ID has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "id")) {
+ if (value -> type != omapi_datatype_int)
+ return ISC_R_INVALIDARG;
+ m -> id = value -> u.integer;
+ return ISC_R_SUCCESS;
+
+ /* Remote transaction ID has to be an integer. */
+ } else if (!omapi_ds_strcmp (name, "rid")) {
+ if (value -> type != omapi_datatype_int)
+ return ISC_R_INVALIDARG;
+ m -> rid = value -> u.integer;
+ return ISC_R_SUCCESS;
+ }
+
+ /* Try to find some inner object that can take the value. */
+ if (h -> inner && h -> inner -> type -> set_value) {
+ status = ((*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value));
+ if (status == ISC_R_SUCCESS)
+ return status;
+ }
+
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_message_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_message_object_t *m;
+ if (h -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ m = (omapi_message_object_t *)h;
+
+ /* Look for values that are in the message data structure. */
+ if (!omapi_ds_strcmp (name, "authlen"))
+ return omapi_make_int_value (value, name, (int)m -> authlen,
+ MDL);
+ else if (!omapi_ds_strcmp (name, "authenticator")) {
+ if (m -> authenticator)
+ return omapi_make_value (value, name,
+ m -> authenticator, MDL);
+ else
+ return ISC_R_NOTFOUND;
+ } else if (!omapi_ds_strcmp (name, "authid")) {
+ return omapi_make_int_value (value,
+ name, (int)m -> authid, MDL);
+ } else if (!omapi_ds_strcmp (name, "op")) {
+ return omapi_make_int_value (value, name, (int)m -> op, MDL);
+ } else if (!omapi_ds_strcmp (name, "handle")) {
+ return omapi_make_int_value (value, name, (int)m -> h, MDL);
+ } else if (!omapi_ds_strcmp (name, "id")) {
+ return omapi_make_int_value (value, name, (int)m -> id, MDL);
+ } else if (!omapi_ds_strcmp (name, "rid")) {
+ return omapi_make_int_value (value, name, (int)m -> rid, MDL);
+ }
+
+ /* See if there's an inner object that has the value. */
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_message_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ int i;
+
+ omapi_message_object_t *m;
+ if (h -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ m = (omapi_message_object_t *)h;
+ if (m -> authenticator) {
+ omapi_typed_data_dereference (&m -> authenticator, file, line);
+ }
+ if (!m -> prev && omapi_registered_messages != m)
+ omapi_message_unregister (h);
+ if (m -> id_object)
+ omapi_object_dereference (&m -> id_object, file, line);
+ if (m -> object)
+ omapi_object_dereference (&m -> object, file, line);
+ if (m -> notify_object)
+ omapi_object_dereference (&m -> notify_object, file, line);
+ if (m -> protocol_object)
+ omapi_protocol_dereference (&m -> protocol_object, file, line);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_message_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ omapi_message_object_t *m;
+ if (h -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ m = (omapi_message_object_t *)h;
+
+ if (!strcmp (name, "status")) {
+ if (m -> notify_object &&
+ m -> notify_object -> type -> signal_handler)
+ return ((m -> notify_object -> type -> signal_handler))
+ (m -> notify_object, name, ap);
+ else if (m -> object && m -> object -> type -> signal_handler)
+ return ((m -> object -> type -> signal_handler))
+ (m -> object, name, ap);
+ }
+ if (h -> inner && h -> inner -> type -> signal_handler)
+ return (*(h -> inner -> type -> signal_handler)) (h -> inner,
+ name, ap);
+ return ISC_R_NOTFOUND;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_message_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *m)
+{
+ int i;
+
+ if (m -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+
+ if (m -> inner && m -> inner -> type -> stuff_values)
+ return (*(m -> inner -> type -> stuff_values)) (c, id,
+ m -> inner);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_message_register (omapi_object_t *mo)
+{
+ omapi_message_object_t *m;
+
+ if (mo -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ m = (omapi_message_object_t *)mo;
+
+ /* Already registered? */
+ if (m -> prev || m -> next || omapi_registered_messages == m)
+ return ISC_R_INVALIDARG;
+
+ if (omapi_registered_messages) {
+ omapi_object_reference
+ ((omapi_object_t **)&m -> next,
+ (omapi_object_t *)omapi_registered_messages, MDL);
+ omapi_object_reference
+ ((omapi_object_t **)&omapi_registered_messages -> prev,
+ (omapi_object_t *)m, MDL);
+ omapi_object_dereference
+ ((omapi_object_t **)&omapi_registered_messages, MDL);
+ }
+ omapi_object_reference
+ ((omapi_object_t **)&omapi_registered_messages,
+ (omapi_object_t *)m, MDL);
+ return ISC_R_SUCCESS;;
+}
+
+isc_result_t omapi_message_unregister (omapi_object_t *mo)
+{
+ omapi_message_object_t *m;
+ omapi_message_object_t *n;
+
+ if (mo -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ m = (omapi_message_object_t *)mo;
+
+ /* Not registered? */
+ if (!m -> prev && omapi_registered_messages != m)
+ return ISC_R_INVALIDARG;
+
+ n = (omapi_message_object_t *)0;
+ if (m -> next) {
+ omapi_object_reference ((omapi_object_t **)&n,
+ (omapi_object_t *)m -> next, MDL);
+ omapi_object_dereference ((omapi_object_t **)&m -> next, MDL);
+ }
+ if (m -> prev) {
+ omapi_message_object_t *tmp = (omapi_message_object_t *)0;
+ omapi_object_reference ((omapi_object_t **)&tmp,
+ (omapi_object_t *)m -> prev, MDL);
+ omapi_object_dereference ((omapi_object_t **)&m -> prev, MDL);
+ if (tmp -> next)
+ omapi_object_dereference
+ ((omapi_object_t **)&tmp -> next, MDL);
+ if (n)
+ omapi_object_reference
+ ((omapi_object_t **)&tmp -> next,
+ (omapi_object_t *)n, MDL);
+ omapi_object_dereference ((omapi_object_t **)&tmp, MDL);
+ } else {
+ omapi_object_dereference
+ ((omapi_object_t **)&omapi_registered_messages, MDL);
+ if (n)
+ omapi_object_reference
+ ((omapi_object_t **)&omapi_registered_messages,
+ (omapi_object_t *)n, MDL);
+ }
+ if (n)
+ omapi_object_dereference ((omapi_object_t **)&n, MDL);
+ return ISC_R_SUCCESS;
+}
+
+#ifdef DEBUG_PROTOCOL
+static const char *omapi_message_op_name(int op) {
+ switch (op) {
+ case OMAPI_OP_OPEN: return "OMAPI_OP_OPEN";
+ case OMAPI_OP_REFRESH: return "OMAPI_OP_REFRESH";
+ case OMAPI_OP_UPDATE: return "OMAPI_OP_UPDATE";
+ case OMAPI_OP_STATUS: return "OMAPI_OP_STATUS";
+ case OMAPI_OP_DELETE: return "OMAPI_OP_DELETE";
+ case OMAPI_OP_NOTIFY: return "OMAPI_OP_NOTIFY";
+ default: return "(unknown op)";
+ }
+}
+#endif
+
+static isc_result_t
+omapi_message_process_internal (omapi_object_t *, omapi_object_t *);
+
+isc_result_t omapi_message_process (omapi_object_t *mo, omapi_object_t *po)
+{
+ isc_result_t status;
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ unsigned long previous_outstanding = dmalloc_outstanding;
+#endif
+
+ status = omapi_message_process_internal (mo, po);
+
+#if defined (DEBUG_MEMORY_LEAKAGE) && 0
+ log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
+ dmalloc_generation,
+ dmalloc_outstanding - previous_outstanding,
+ dmalloc_outstanding, dmalloc_longterm);
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE) && 0
+ dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) && 0
+ dump_rc_history ();
+#endif
+
+ return status;
+}
+
+static isc_result_t
+omapi_message_process_internal (omapi_object_t *mo, omapi_object_t *po)
+{
+ omapi_message_object_t *message, *m;
+ omapi_object_t *object = (omapi_object_t *)0;
+ omapi_value_t *tv = (omapi_value_t *)0;
+ unsigned long create, update, exclusive;
+ unsigned long wsi;
+ isc_result_t status, waitstatus;
+ omapi_object_type_t *type;
+
+ if (mo -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ message = (omapi_message_object_t *)mo;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_message_process(): "
+ "op=%s handle=%#x id=%#x rid=%#x",
+ omapi_message_op_name (message -> op),
+ message -> h, message -> id, message -> rid);
+#endif
+
+ if (message -> rid) {
+ for (m = omapi_registered_messages; m; m = m -> next)
+ if (m -> id == message -> rid)
+ break;
+ /* If we don't have a real message corresponding to
+ the message ID to which this message claims it is a
+ response, something's fishy. */
+ if (!m)
+ return ISC_R_NOTFOUND;
+ /* The authenticator on responses must match the initial
+ message. */
+ if (message -> authid != m -> authid)
+ return ISC_R_NOTFOUND;
+ } else {
+ m = (omapi_message_object_t *)0;
+
+ /* All messages must have an authenticator, with the exception
+ of messages that are opening a new authenticator. */
+ if (omapi_protocol_authenticated (po) &&
+ !message -> id_object &&
+ message -> op != OMAPI_OP_OPEN) {
+ return omapi_protocol_send_status
+ (po, message -> id_object, ISC_R_NOKEYS,
+ message -> id, "No authenticator on message");
+ }
+ }
+
+ switch (message -> op) {
+ case OMAPI_OP_OPEN:
+ if (m) {
+ return omapi_protocol_send_status
+ (po, message -> id_object, ISC_R_INVALIDARG,
+ message -> id, "OPEN can't be a response");
+ }
+
+ /* Get the type of the requested object, if one was
+ specified. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "type", &tv);
+ if (status == ISC_R_SUCCESS &&
+ (tv -> value -> type == omapi_datatype_data ||
+ tv -> value -> type == omapi_datatype_string)) {
+ for (type = omapi_object_types;
+ type; type = type -> next)
+ if (!omapi_td_strcmp (tv -> value,
+ type -> name))
+ break;
+ } else
+ type = (omapi_object_type_t *)0;
+ if (tv)
+ omapi_value_dereference (&tv, MDL);
+
+ /* If this object had no authenticator, the requested object
+ must be an authenticator object. */
+ if (omapi_protocol_authenticated (po) &&
+ !message -> id_object &&
+ type != omapi_type_auth_key) {
+ return omapi_protocol_send_status
+ (po, message -> id_object, ISC_R_NOKEYS,
+ message -> id, "No authenticator on message");
+ }
+
+ /* Get the create flag. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "create", &tv);
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_get_int_value (&create, tv -> value);
+ omapi_value_dereference (&tv, MDL);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "invalid create flag value");
+ }
+ } else
+ create = 0;
+
+ /* Get the update flag. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "update", &tv);
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_get_int_value (&update, tv -> value);
+ omapi_value_dereference (&tv, MDL);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "invalid update flag value");
+ }
+ } else
+ update = 0;
+
+ /* Get the exclusive flag. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "exclusive", &tv);
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_get_int_value (&exclusive, tv -> value);
+ omapi_value_dereference (&tv, MDL);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "invalid exclusive flag value");
+ }
+ } else
+ exclusive = 0;
+
+ /* If we weren't given a type, look the object up with
+ the handle. */
+ if (!type) {
+ if (create) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ ISC_R_INVALIDARG,
+ message -> id,
+ "type required on create");
+ }
+ goto refresh;
+ }
+
+ /* If the type doesn't provide a lookup method, we can't
+ look up the object. */
+ if (!type -> lookup) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ ISC_R_NOTIMPLEMENTED, message -> id,
+ "unsearchable object type");
+ }
+
+ status = (*(type -> lookup)) (&object, message -> id_object,
+ message -> object);
+
+ if (status != ISC_R_SUCCESS &&
+ status != ISC_R_NOTFOUND &&
+ status != ISC_R_NOKEYS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "object lookup failed");
+ }
+
+ /* If we didn't find the object and we aren't supposed to
+ create it, return an error. */
+ if (status == ISC_R_NOTFOUND && !create) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ ISC_R_NOTFOUND, message -> id,
+ "no object matches specification");
+ }
+
+ /* If we found an object, we're supposed to be creating an
+ object, and we're not supposed to have found an object,
+ return an error. */
+ if (status == ISC_R_SUCCESS && create && exclusive) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ ISC_R_EXISTS, message -> id,
+ "specified object already exists");
+ }
+
+ /* If we're creating the object, do it now. */
+ if (!object) {
+ status = omapi_object_create (&object,
+ message -> id_object,
+ type);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't create new object");
+ }
+ }
+
+ /* If we're updating it, do so now. */
+ if (create || update) {
+ /* This check does not belong here. */
+ if (object -> type == omapi_type_auth_key) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't update object");
+ }
+
+ status = omapi_object_update (object,
+ message -> id_object,
+ message -> object,
+ message -> h);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't update object");
+ }
+ }
+
+ /* If this is an authenticator object, add it to the active
+ set for the connection. */
+ if (object -> type == omapi_type_auth_key) {
+ omapi_handle_t handle;
+ status = omapi_object_handle (&handle, object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't select authenticator");
+ }
+
+ status = omapi_protocol_add_auth (po, object, handle);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't select authenticator");
+ }
+ }
+
+ /* Now send the new contents of the object back in
+ response. */
+ goto send;
+
+ case OMAPI_OP_REFRESH:
+ refresh:
+ status = omapi_handle_lookup (&object, message -> h);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "no matching handle");
+ }
+ send:
+ status = omapi_protocol_send_update (po, message -> id_object,
+ message -> id, object);
+ omapi_object_dereference (&object, MDL);
+ return status;
+
+ case OMAPI_OP_UPDATE:
+ if (m && m -> object) {
+ omapi_object_reference (&object, m -> object, MDL);
+ } else {
+ status = omapi_handle_lookup (&object, message -> h);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "no matching handle");
+ }
+ }
+
+ if (object -> type == omapi_type_auth_key ||
+ (object -> inner &&
+ object -> inner -> type == omapi_type_auth_key)) {
+ if (!m) {
+ omapi_object_dereference (&object, MDL);
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "cannot update authenticator");
+ }
+
+ status = omapi_protocol_add_auth (po, object,
+ message -> h);
+ } else {
+ status = omapi_object_update (object,
+ message -> id_object,
+ message -> object,
+ message -> h);
+ }
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference (&object, MDL);
+ if (!message -> rid)
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "can't update object");
+ if (m)
+ omapi_signal ((omapi_object_t *)m,
+ "status", status,
+ (omapi_typed_data_t *)0);
+ return ISC_R_SUCCESS;
+ }
+ if (!message -> rid)
+ status = omapi_protocol_send_status
+ (po, message -> id_object, ISC_R_SUCCESS,
+ message -> id, (char *)0);
+ if (m)
+ omapi_signal ((omapi_object_t *)m,
+ "status", ISC_R_SUCCESS,
+ (omapi_typed_data_t *)0);
+ return status;
+
+ case OMAPI_OP_NOTIFY:
+ return omapi_protocol_send_status
+ (po, message -> id_object, ISC_R_NOTIMPLEMENTED,
+ message -> id, "notify not implemented yet");
+
+ case OMAPI_OP_STATUS:
+ /* The return status of a request. */
+ if (!m)
+ return ISC_R_UNEXPECTED;
+
+ /* Get the wait status. */
+ status = omapi_get_value_str (mo, message -> id_object,
+ "result", &tv);
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_get_int_value (&wsi, tv -> value);
+ waitstatus = wsi;
+ omapi_value_dereference (&tv, MDL);
+ if (status != ISC_R_SUCCESS)
+ waitstatus = ISC_R_UNEXPECTED;
+ } else
+ waitstatus = ISC_R_UNEXPECTED;
+
+ status = omapi_get_value_str (mo, message -> id_object,
+ "message", &tv);
+ omapi_signal ((omapi_object_t *)m, "status", waitstatus, tv);
+ if (status == ISC_R_SUCCESS)
+ omapi_value_dereference (&tv, MDL);
+ return ISC_R_SUCCESS;
+
+ case OMAPI_OP_DELETE:
+ status = omapi_handle_lookup (&object, message -> h);
+ if (status != ISC_R_SUCCESS) {
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ status, message -> id,
+ "no matching handle");
+ }
+
+ if (!object -> type -> remove)
+ return omapi_protocol_send_status
+ (po, message -> id_object,
+ ISC_R_NOTIMPLEMENTED, message -> id,
+ "no remove method for object");
+
+ status = (*(object -> type -> remove)) (object,
+ message -> id_object);
+ omapi_object_dereference (&object, MDL);
+
+ return omapi_protocol_send_status (po, message -> id_object,
+ status, message -> id,
+ (char *)0);
+ }
+ return ISC_R_NOTIMPLEMENTED;
+}
diff --git a/contrib/isc-dhcp/omapip/mrtrace.c b/contrib/isc-dhcp/omapip/mrtrace.c
new file mode 100644
index 000000000000..c3539900edfe
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/mrtrace.c
@@ -0,0 +1,488 @@
+/* mrtrace.c
+
+ Subroutines that support minires tracing... */
+
+/*
+ * Copyright (c) 2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon, as part of a project for Nominum, Inc. To learn more
+ * about the Internet Software Consortium, see http://www.isc.org/. To
+ * learn more about Nominum, Inc., see ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+#include "minires/minires.h"
+#include "arpa/nameser.h"
+
+static void trace_mr_output_input (trace_type_t *, unsigned, char *);
+static void trace_mr_output_stop (trace_type_t *);
+static void trace_mr_input_input (trace_type_t *, unsigned, char *);
+static void trace_mr_input_stop (trace_type_t *);
+static void trace_mr_statp_input (trace_type_t *, unsigned, char *);
+static void trace_mr_statp_stop (trace_type_t *);
+static void trace_mr_randomid_input (trace_type_t *, unsigned, char *);
+static void trace_mr_randomid_stop (trace_type_t *);
+trace_type_t *trace_mr_output;
+trace_type_t *trace_mr_input;
+trace_type_t *trace_mr_statp;
+trace_type_t *trace_mr_randomid;
+ssize_t trace_mr_send (int, void *, size_t, int);
+ssize_t trace_mr_read_playback (struct sockaddr_in *, void *, size_t);
+void trace_mr_read_record (struct sockaddr_in *, void *, ssize_t);
+ssize_t trace_mr_recvfrom (int s, void *, size_t, int,
+ struct sockaddr *, SOCKLEN_T *);
+ssize_t trace_mr_read (int, void *, size_t);
+int trace_mr_connect (int s, struct sockaddr *, SOCKLEN_T);
+int trace_mr_socket (int, int, int);
+int trace_mr_bind (int, struct sockaddr *, SOCKLEN_T);
+int trace_mr_close (int);
+time_t trace_mr_time (time_t *);
+int trace_mr_select (int, fd_set *, fd_set *, fd_set *, struct timeval *);
+unsigned int trace_mr_res_randomid (unsigned int);
+
+extern time_t cur_time;
+
+#if defined (TRACING)
+void trace_mr_init ()
+{
+ trace_mr_output = trace_type_register ("mr-output", (void *)0,
+ trace_mr_output_input,
+ trace_mr_output_stop, MDL);
+ trace_mr_input = trace_type_register ("mr-input", (void *)0,
+ trace_mr_input_input,
+ trace_mr_input_stop, MDL);
+ trace_mr_statp = trace_type_register ("mr-statp", (void *)0,
+ trace_mr_statp_input,
+ trace_mr_statp_stop, MDL);
+ trace_mr_randomid = trace_type_register ("mr-randomid", (void *)0,
+ trace_mr_randomid_input,
+ trace_mr_randomid_stop, MDL);
+}
+
+void trace_mr_statp_setup (res_state statp)
+{
+ unsigned buflen = 0;
+ char *buf = (char *)0;
+ isc_result_t status;
+ u_int32_t id;
+ int i;
+
+ if (trace_playback ()) {
+ int nscount;
+ status = trace_get_packet (&trace_mr_statp, &buflen, &buf);
+ if (status != ISC_R_SUCCESS) {
+ log_error ("trace_mr_statp: no statp packet found.");
+ return;
+ }
+ nscount = buflen / sizeof (struct in_addr);
+ if (nscount * (sizeof (struct in_addr)) != buflen ||
+ nscount < 1) {
+ log_error ("trace_mr_statp: bogus length: %d",
+ buflen);
+ return;
+ }
+ if (nscount > MAXNS)
+ nscount = MAXNS;
+ for (i = 0; i < nscount; i++) {
+#if defined (HAVE_SA_LEN)
+ statp -> nsaddr_list [i].sin_len =
+ sizeof (struct sockaddr_in);
+#endif
+ memset (&statp -> nsaddr_list [i].sin_zero, 0,
+ sizeof statp -> nsaddr_list [i].sin_zero);
+ statp -> nsaddr_list [i].sin_port = htons (53); /*XXX*/
+ statp -> nsaddr_list [i].sin_family = AF_INET;
+ memcpy (&statp -> nsaddr_list [i].sin_addr,
+ (buf + i * (sizeof (struct in_addr))),
+ sizeof (struct in_addr));
+ }
+ statp -> nscount = nscount;
+ dfree (buf, MDL);
+ buf = (char *)0;
+ }
+ if (trace_record ()) {
+ trace_iov_t *iov;
+ iov = dmalloc ((statp -> nscount *
+ sizeof (trace_iov_t)), MDL);
+ if (!iov) {
+ trace_stop ();
+ log_error ("No memory for statp iov.");
+ return;
+ }
+ for (i = 0; i < statp -> nscount; i++) {
+ iov [i].buf =
+ (char *)&statp -> nsaddr_list [i].sin_addr;
+ iov [i].len = sizeof (struct in_addr);
+ }
+ trace_write_packet_iov (trace_mr_statp, i, iov, MDL);
+ dfree (iov, MDL);
+ }
+}
+#endif
+
+ssize_t trace_mr_send (int fd, void *msg, size_t len, int flags)
+{
+ ssize_t rv;
+#if defined (TRACING)
+ isc_result_t status;
+ unsigned buflen = 0;
+ char *inbuf = (char *)0;
+ u_int32_t result;
+ u_int32_t sflags;
+
+ if (trace_playback()) {
+ status = trace_get_packet (&trace_mr_output, &buflen, &inbuf);
+ if (status != ISC_R_SUCCESS) {
+ log_error ("trace_mr_recvfrom: no input found.");
+ errno = ECONNREFUSED;
+ return -1;
+ }
+ if (buflen < sizeof result) {
+ log_error ("trace_mr_recvfrom: data too short.");
+ errno = ECONNREFUSED;
+ dfree (inbuf, MDL);
+ return -1;
+ }
+ memcpy (&result, inbuf, sizeof result);
+ rv = ntohl (result);
+ dfree (inbuf, MDL);
+ } else
+#endif
+ rv = send (fd, msg, len, flags);
+#if defined (TRACING)
+ if (trace_record ()) {
+ trace_iov_t iov [3];
+ result = htonl (rv);
+ sflags = htonl (flags);
+ iov [0].len = sizeof result;
+ iov [0].buf = (char *)&result;
+ iov [1].len = sizeof sflags;
+ iov [1].buf = (char *)&flags;
+ iov [2].len = len;
+ iov [2].buf = msg;
+ trace_write_packet_iov (trace_mr_output, 2, iov, MDL);
+ }
+#endif
+ return rv;
+}
+
+#if defined (TRACING)
+ssize_t trace_mr_read_playback (struct sockaddr_in *from,
+ void *buf, size_t nbytes)
+{
+ isc_result_t status;
+ unsigned buflen = 0, left;
+ char *inbuf = (char *)0;
+ char *bufp;
+ u_int32_t result;
+
+ status = trace_get_packet (&trace_mr_input, &buflen, &inbuf);
+ if (status != ISC_R_SUCCESS) {
+ log_error ("trace_mr_recvfrom: no input found.");
+ errno = ECONNREFUSED;
+ return -1;
+ }
+ if (buflen < sizeof result) {
+ log_error ("trace_mr_recvfrom: data too short.");
+ errno = ECONNREFUSED;
+ dfree (inbuf, MDL);
+ return -1;
+ }
+ bufp = inbuf;
+ left = buflen;
+ memcpy (&result, bufp, sizeof result);
+ result = ntohl (result);
+ bufp += sizeof result;
+ left -= sizeof result;
+ if (result == 0) {
+ if (left < ((sizeof from -> sin_port) +
+ sizeof (from -> sin_addr))) {
+ log_error ("trace_mr_recvfrom: data too short.");
+ errno = ECONNREFUSED;
+ dfree (inbuf, MDL);
+ return -1;
+ }
+ if (from)
+ memcpy (&from -> sin_addr, bufp,
+ sizeof from -> sin_addr);
+ bufp += sizeof from -> sin_addr;
+ left -= sizeof from -> sin_addr;
+ if (from)
+ memcpy (&from -> sin_port, bufp,
+ sizeof from -> sin_port);
+ bufp += sizeof from -> sin_port;
+ left -= sizeof from -> sin_port;
+ if (from) {
+ from -> sin_family = AF_INET;
+#if defined(HAVE_SA_LEN)
+ from -> sin_len = sizeof (struct sockaddr_in);
+#endif
+ memset (from -> sin_zero, 0, sizeof from -> sin_zero);
+ }
+ if (left > nbytes) {
+ log_error ("trace_mr_recvfrom: too much%s",
+ " data.");
+ errno = ECONNREFUSED;
+ dfree (inbuf, MDL);
+ return -1;
+ }
+ memcpy (buf, bufp, left);
+ dfree (inbuf, MDL);
+ return left;
+ }
+ errno = ECONNREFUSED;
+ return -1;
+}
+
+void trace_mr_read_record (struct sockaddr_in *from, void *buf, ssize_t rv)
+{
+ trace_iov_t iov [4];
+ u_int32_t result;
+ int iolen = 0;
+ static char zero [4] = { 0, 0, 0, 0 };
+
+ if (rv < 0)
+ result = htonl (errno); /* XXX */
+ else
+ result = 0;
+ iov [iolen].buf = (char *)&result;
+ iov [iolen++].len = sizeof result;
+ if (rv > 0) {
+ if (from) {
+ iov [iolen].buf = (char *)&from -> sin_addr;
+ iov [iolen++].len = sizeof from -> sin_addr;
+ iov [iolen].buf = (char *)&from -> sin_port;
+ iov [iolen++].len = sizeof from -> sin_port;
+ } else {
+ iov [iolen].buf = zero;
+ iov [iolen++].len = sizeof from -> sin_addr;
+ iov [iolen].buf = zero;
+ iov [iolen++].len = sizeof from -> sin_port;
+ }
+
+ iov [iolen].buf = buf;
+ iov [iolen++].len = rv;
+ }
+ trace_write_packet_iov (trace_mr_input, iolen, iov, MDL);
+}
+#endif
+
+ssize_t trace_mr_recvfrom (int s, void *buf, size_t len, int flags,
+ struct sockaddr *from, SOCKLEN_T *fromlen)
+{
+ ssize_t rv;
+
+#if defined (TRACING)
+ if (trace_playback ())
+ rv = trace_mr_read_playback ((struct sockaddr_in *)from,
+ buf, len);
+ else
+#endif
+ rv = recvfrom (s, buf, len, flags, from, fromlen);
+#if defined (TRACING)
+ if (trace_record ()) {
+ trace_mr_read_record ((struct sockaddr_in *)from, buf, rv);
+ }
+#endif
+ return rv;
+}
+
+ssize_t trace_mr_read (int d, void *buf, size_t nbytes)
+{
+ ssize_t rv;
+
+#if defined (TRACING)
+ if (trace_playback ())
+ rv = trace_mr_read_playback ((struct sockaddr_in *)0,
+ buf, nbytes);
+ else
+#endif
+ rv = read (d, buf, nbytes);
+#if defined (TRACING)
+ if (trace_record ()) {
+ trace_mr_read_record ((struct sockaddr_in *)0, buf, rv);
+ }
+#endif
+ return rv;
+}
+
+int trace_mr_connect (int s, struct sockaddr *name, SOCKLEN_T namelen)
+{
+#if defined (TRACING)
+ if (!trace_playback ())
+#endif
+ return connect (s, name, namelen);
+#if defined (TRACING)
+ return 0;
+#endif
+}
+
+int trace_mr_socket (int domain, int type, int protocol)
+{
+#if defined (TRACING)
+ if (!trace_playback ())
+#endif
+ return socket (domain, type, protocol);
+#if defined (TRACING)
+ return 100;
+#endif
+}
+
+int trace_mr_bind (int s, struct sockaddr *name, SOCKLEN_T namelen)
+{
+#if defined (TRACING)
+ if (!trace_playback ())
+#endif
+ return bind (s, name, namelen);
+#if defined (TRACING)
+ return 0;
+#endif
+}
+
+int trace_mr_close (int s)
+{
+#if defined (TRACING)
+ if (!trace_playback ())
+#endif
+ return close (s);
+#if defined (TRACING)
+ return 0;
+#endif
+}
+
+time_t trace_mr_time (time_t *tp)
+{
+#if defined (TRACING)
+ if (trace_playback ()) {
+ if (tp)
+ *tp = cur_time;
+ return cur_time;
+ }
+#endif
+ return time (tp);
+}
+
+int trace_mr_select (int s, fd_set *r, fd_set *w, fd_set *x, struct timeval *t)
+{
+#if defined (TRACING)
+ trace_type_t *ttp = (trace_type_t *)0;
+
+ if (trace_playback ()) {
+ time_t nct = trace_snoop_time (&ttp);
+ time_t secr = t -> tv_sec;
+ t -> tv_sec = nct - cur_time;
+ if (t -> tv_sec > secr)
+ return 0;
+ if (ttp == trace_mr_input)
+ return 1;
+ return 0;
+ }
+#endif
+ return select (s, r, w, x, t);
+}
+
+unsigned int trace_mr_res_randomid (unsigned int oldid)
+{
+ u_int32_t id;
+ int rid = oldid;
+#if defined (TRACING)
+ unsigned buflen = 0;
+ char *buf = (char *)0;
+ isc_result_t status;
+
+ if (trace_playback ()) {
+ int nscount;
+ status = trace_get_packet (&trace_mr_randomid, &buflen, &buf);
+ if (status != ISC_R_SUCCESS) {
+ log_error ("trace_mr_statp: no statp packet found.");
+ return oldid;
+ }
+ if (buflen != sizeof id) {
+ log_error ("trace_mr_randomid: bogus length: %d",
+ buflen);
+ return oldid;
+ }
+ memcpy (&id, buf, sizeof id);
+ dfree (buf, MDL);
+ buf = (char *)0;
+ rid = ntohl (id);
+ }
+ if (trace_record ()) {
+ id = htonl (rid);
+ trace_write_packet (trace_mr_randomid,
+ sizeof id, (char *)&id, MDL);
+ }
+#endif
+ return rid;
+}
+
+#if defined (TRACING)
+static void trace_mr_output_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+}
+
+static void trace_mr_output_stop (trace_type_t *ttype)
+{
+}
+
+static void trace_mr_input_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ log_error ("unaccounted-for minires input.");
+}
+
+static void trace_mr_input_stop (trace_type_t *ttype)
+{
+}
+
+static void trace_mr_statp_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ log_error ("unaccounted-for minires statp input.");
+}
+
+static void trace_mr_statp_stop (trace_type_t *ttype)
+{
+}
+
+static void trace_mr_randomid_input (trace_type_t *ttype,
+ unsigned length, char *buf)
+{
+ log_error ("unaccounted-for minires randomid input.");
+}
+
+static void trace_mr_randomid_stop (trace_type_t *ttype)
+{
+}
+#endif
diff --git a/contrib/isc-dhcp/omapip/omapi.3 b/contrib/isc-dhcp/omapip/omapi.3
new file mode 100644
index 000000000000..112621df3fd1
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/omapi.3
@@ -0,0 +1,254 @@
+.\" omapi.3
+.\"
+.\" Copyright (c) 2000-2001 Internet Software Consortium.
+.\" 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+.\"
+.\" This software has been written for the Internet Software Consortium
+.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+.\" To learn more about the Internet Software Consortium, see
+.\" ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+.\" ``http://www.nominum.com''.
+.TH omapi 3
+.SH NAME
+OMAPI - Object Management Application Programming Interface
+.SH DESCRIPTION
+.PP
+OMAPI is an programming layer designed for controlling remote
+applications, and for querying them for their state. It is currently
+used by the ISC DHCP server and this outline addresses the parts of
+OMAPI appropriate to the clients of DHCP server. It does this by also
+describing the use of a thin API layered on top of OMAPI called
+'dhcpctl'
+.PP
+OMAPI uses TCP/IP as the transport for server communication, and
+security can be imposed by having the client and server
+cryptographically sign messages using a shared secret.
+.PP
+dhcpctl works by presenting the client with handles to objects that
+act as surrogates for the real objects in the server. For example a
+client will create a handle for a lease object, and will request the
+server to fill the lease handle's state. The client application can
+then pull details such as the lease expiration time from the lease
+handle.
+.PP
+Modifications can be made to the server state by creating handles to
+new objects, or by modifying attributes of handles to existing
+objects, and then instructing the server to update itself according to
+the changes made.
+.SH USAGE
+.PP
+The client application must always call dhcpctl_initialize() before
+making calls to any other dhcpctl functions. This initializes
+various internal data structures.
+.PP
+To create the connection to the server the client must use
+dhcpctl_connect() function. As well as making the physical connection
+it will also set up the connection data structures to do
+authentication on each message, if that is required.
+.PP
+All the dhcpctl functions return an integer value of type
+isc_result_t. A successful call will yield a result of
+ISC_R_SUCCESS. If the call fails for a reason local to the client
+(e.g. insufficient local memory, or invalid arguments to the call)
+then the return value of the dhcpctl function will show that. If the
+call succeeds but the server couldn't process the request the error
+value from the server is returned through another way, shown below.
+.PP
+The easiest way to understand dhcpctl is to see it in action. The
+following program is fully functional, but almost all error checking
+has been removed to make is shorter and easier to understand. This
+program will query the server running on the localhost for the details
+of the lease for IP address 10.0.0.101. It will then print out the time
+the lease ends.
+.PP
+.nf
+ #include <stdarg.h>
+ #include <sys/time.h>
+ #include <sys/socket.h>
+ #include <stdio.h>
+ #include <netinet/in.h>
+
+ #include <isc/result.h>
+ #include <dhcpctl/dhcpctl.h>
+
+ int main (int argc, char **argv) {
+ dhcpctl_data_string ipaddrstring = NULL;
+ dhcpctl_data_string value = NULL;
+.fi
+.PP
+All modifications of handles and all accesses of handle data happen
+via dhcpctl_data_string objects.
+.PP
+.nf
+ dhcpctl_handle connection = NULL;
+ dhcpctl_handle lease = NULL;
+ isc_result_t waitstatus;
+ struct in_addr convaddr;
+ time_t thetime;
+
+ dhcpctl_initialize ();
+.fi
+.PP
+Required first step.
+.PP
+.nf
+ dhcpctl_connect (&connection, "127.0.0.1",
+ 7911, 0);
+.fi
+.PP
+Sets up the connection to the server. The server normally listens on
+port 7911 unless configured to do otherwise.
+.PP
+.nf
+ dhcpctl_new_object (&lease, connection,
+ "lease");
+.fi
+.PP
+Here we create a handle to a lease. This call just sets up local data
+structure. The server hasn't yet made any association between the
+client's data structure and any lease it has.
+.PP
+.nf
+ memset (&ipaddrstring, 0, sizeof
+ ipaddrstring);
+
+ inet_pton(AF_INET, "10.0.0.101",
+ &convaddr);
+
+ omapi_data_string_new (&ipaddrstring,
+ 4, MDL);
+.fi
+.PP
+Create a new data string to storing in the handle.
+.PP
+.nf
+ memcpy(ipaddrstring->value, &convaddr.s_addr, 4);
+
+ dhcpctl_set_value (lease, ipaddrstring,
+ "ip-address");
+.fi
+.PP
+We're setting the ip-address attribute of the lease handle to the
+given address. We've not set any other attributes so when the server
+makes the association the ip address will be all it uses to look up
+the lease in its tables.
+.PP
+.nf
+ dhcpctl_open_object (lease, connection, 0);
+.fi
+.PP
+Here we prime the connection with the request to look up the lease in
+the server and fill up the local handle with the attributes the server
+will send over in its answer.
+.PP
+.nf
+ dhcpctl_wait_for_completion (lease,
+ &waitstatus);
+.fi
+.PP
+This call causes the message to get sent to the server (the message to
+look up the lease and send back the attribute values in the
+answer). The value in the variable waitstatus when the function
+returns will be the result from the server. If the message could
+not be processed properly by the server then the error will be
+reflected here.
+.PP
+.nf
+ if (waitstatus != ISC_R_SUCCESS) {
+ /* server not authoritative */
+ exit (0);
+ }
+
+ dhcpctl_data_string_dereference(&ipaddrstring,
+ MDL);
+.fi
+.PP
+Clean-up memory we no longer need.
+.PP
+.nf
+ dhcpctl_get_value (&value, lease, "ends");
+.fi
+.PP
+Get the attribute named ``ends'' from the lease handle. This is a
+4-byte integer of the time (in unix epoch seconds) that the lease
+will expire.
+.PP
+.nf
+
+ memcpy(&thetime, value->value, value->len);
+ dhcpctl_data_string_dereference(&value, MDL);
+
+ fprintf (stdout, "ending time is %s",
+ ctime(&thetime));
+ }
+
+.fi
+.SH AUTHENTICATION
+If the server demands authenticated connections then before opening
+the connection the user must call dhcpctl_new_authenticator.
+.PP
+.nf
+ dhcpctl_handle authenticator = NULL;
+ const char *keyname = "a-key-name";
+ const char *algorithm = "hmac-md5";
+ const char *secret = "a-shared-secret";
+
+ dhcpctl_new_authenticator (&authenticator,
+ keyname,
+ algorithm,
+ secret,
+ strlen(secret) + 1);
+.fi
+.PP
+The keyname, algorithm and secret must all match what is specified in
+the server's dhcpd.conf file:
+.PP
+.nf
+ key "a-key-name" {
+ algorithm hmac-md5;
+ secret "a-shared-secret";
+ };
+
+ # Set the omapi-key value to use
+ # authenticated connections
+ omapi-key "a-key-name";
+.fi
+.PP
+The authenticator handle that is created by the call to
+dhcpctl_new_authenticator must be given as the last (the 4th) argument
+to the call to dhcpctl_connect(). All messages will then be signed
+with the given secret string using the specified algorithm.
+.SH SEE ALSO
+dhcpctl(3), omapi(3), dhcpd(8), dhclient(8), dhcpd.conf(5), dhclient.conf(5).
+.SH AUTHOR
+.B omapi
+was created by Ted Lemon of Nominum, Inc. Information about Nominum
+and support contracts for DHCP and BIND can be found at
+.B http://www.nominum.com. This documentation was written by James
+Brister of Nominum, Inc.
diff --git a/contrib/isc-dhcp/omapip/protocol.c b/contrib/isc-dhcp/omapip/protocol.c
new file mode 100644
index 000000000000..c61fa195e8c6
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/protocol.c
@@ -0,0 +1,1319 @@
+/* protocol.c
+
+ Functions supporting the object management protocol... */
+
+/*
+ * Copyright (c) 1999-2000 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+OMAPI_OBJECT_ALLOC (omapi_protocol, omapi_protocol_object_t,
+ omapi_type_protocol)
+OMAPI_OBJECT_ALLOC (omapi_protocol_listener, omapi_protocol_listener_object_t,
+ omapi_type_protocol_listener)
+
+isc_result_t omapi_protocol_connect (omapi_object_t *h,
+ const char *server_name,
+ unsigned port,
+ omapi_object_t *a)
+{
+ isc_result_t rstatus, status;
+ omapi_protocol_object_t *obj;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port);
+#endif
+
+ obj = (omapi_protocol_object_t *)0;
+ status = omapi_protocol_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ rstatus = omapi_connect ((omapi_object_t *)obj, server_name, port);
+ if (rstatus != ISC_R_SUCCESS && rstatus != ISC_R_INCOMPLETE) {
+ omapi_protocol_dereference (&obj, MDL);
+ return rstatus;
+ }
+ status = omapi_object_reference (&h -> outer,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_protocol_dereference (&obj, MDL);
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, h, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_protocol_dereference (&obj, MDL);
+ return status;
+ }
+
+ /* If we were passed a default authenticator, store it now. We'll
+ open it once we're connected. */
+ if (a) {
+ obj -> default_auth =
+ dmalloc (sizeof(omapi_remote_auth_t), MDL);
+ if (!obj -> default_auth) {
+ omapi_protocol_dereference (&obj, MDL);
+ return ISC_R_NOMEMORY;
+ }
+
+ obj -> default_auth -> next = (omapi_remote_auth_t *)0;
+ status = omapi_object_reference (&obj -> default_auth -> a,
+ a, MDL);
+ if (status != ISC_R_SUCCESS) {
+ dfree (obj -> default_auth, MDL);
+ omapi_protocol_dereference (&obj, MDL);
+ return status;
+ }
+
+ obj -> insecure = 0;
+ rstatus = ISC_R_INCOMPLETE;
+ } else {
+ obj -> insecure = 1;
+#if 0
+ status = ISC_R_SUCCESS;
+#endif
+ }
+
+ omapi_protocol_dereference (&obj, MDL);
+ return rstatus;
+}
+
+/* Send the protocol introduction message. */
+isc_result_t omapi_protocol_send_intro (omapi_object_t *h,
+ unsigned ver,
+ unsigned hsize)
+{
+ isc_result_t status;
+ omapi_protocol_object_t *p;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_protocol_send_intro()");
+#endif
+
+ if (h -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)h;
+
+ if (!h -> outer || h -> outer -> type != omapi_type_connection)
+ return ISC_R_NOTCONNECTED;
+
+ status = omapi_connection_put_uint32 (h -> outer, ver);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_connection_put_uint32 (h -> outer, hsize);
+
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ /* Require the other end to send an intro - this kicks off the
+ protocol input state machine. */
+ p -> state = omapi_protocol_intro_wait;
+ status = omapi_connection_require (h -> outer, 8);
+ if (status != ISC_R_SUCCESS && status != ISC_R_NOTYET)
+ return status;
+
+ /* Make up an initial transaction ID for this connection. */
+ p -> next_xid = random ();
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_protocol_send_message (omapi_object_t *po,
+ omapi_object_t *id,
+ omapi_object_t *mo,
+ omapi_object_t *omo)
+{
+ omapi_protocol_object_t *p;
+ omapi_object_t *c;
+ omapi_message_object_t *m, *om;
+ omapi_remote_auth_t *ra;
+ omapi_value_t *signature;
+ isc_result_t status;
+ u_int32_t foo;
+ unsigned auth_len;
+
+ if (po -> type != omapi_type_protocol ||
+ !po -> outer || po -> outer -> type != omapi_type_connection ||
+ mo -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ if (omo && omo -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)po;
+ c = (omapi_object_t *)(po -> outer);
+ m = (omapi_message_object_t *)mo;
+ om = (omapi_message_object_t *)omo;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_protocol_send_message()"
+ "op=%ld handle=%#lx id=%#lx rid=%#lx",
+ (long)m -> op,
+ (long)(m -> object ? m -> object -> handle : m -> handle),
+ (long)p -> next_xid, (long)m -> rid);
+#endif
+
+ /* Find the authid to use for this message. */
+ if (id) {
+ for (ra = p -> remote_auth_list; ra; ra = ra -> next) {
+ if (ra -> a == id) {
+ break;
+ }
+ }
+
+ if (!ra)
+ return ISC_R_KEY_UNKNOWN;
+ } else if (p -> remote_auth_list) {
+ ra = p -> default_auth;
+ } else {
+ ra = (omapi_remote_auth_t *)0;
+ }
+
+ if (ra) {
+ m -> authid = ra -> remote_handle;
+ status = omapi_object_reference (&m -> id_object,
+ ra -> a, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ /* Write the ID of the authentication key we're using. */
+ status = omapi_connection_put_uint32 (c, ra ? ra -> remote_handle : 0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Activate the authentication key on the connection. */
+ auth_len = 0;
+ if (ra) {
+ status = omapi_set_object_value (c, (omapi_object_t *)0,
+ "output-authenticator",
+ ra -> a);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ status = omapi_connection_output_auth_length (c, &auth_len);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ /* Write the authenticator length */
+ status = omapi_connection_put_uint32 (c, auth_len);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the opcode. */
+ status = omapi_connection_put_uint32 (c, m -> op);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the handle. If we've been given an explicit handle, use
+ that. Otherwise, use the handle of the object we're sending.
+ The caller is responsible for arranging for one of these handles
+ to be set (or not). */
+ status = omapi_connection_put_uint32 (c, (m -> h
+ ? m -> h
+ : (m -> object
+ ? m -> object -> handle
+ : 0)));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Set and write the transaction ID. */
+ m -> id = p -> next_xid++;
+ status = omapi_connection_put_uint32 (c, m -> id);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the transaction ID of the message to which this is a
+ response, if there is such a message. */
+ status = omapi_connection_put_uint32 (c, om ? om -> id : m -> rid);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Stuff out the name/value pairs specific to this message. */
+ status = omapi_stuff_values (c, id, (omapi_object_t *)m);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the zero-length name that terminates the list of name/value
+ pairs specific to the message. */
+ status = omapi_connection_put_uint16 (c, 0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Stuff out all the published name/value pairs in the object that's
+ being sent in the message, if there is one. */
+ if (m -> object) {
+ status = omapi_stuff_values (c, id, m -> object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ /* Write the zero-length name that terminates the list of name/value
+ pairs for the associated object. */
+ status = omapi_connection_put_uint16 (c, 0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ if (ra) {
+ /* Calculate the message signature. */
+ signature = (omapi_value_t *)0;
+ status = omapi_get_value_str (c, (omapi_object_t *)0,
+ "output-signature", &signature);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Write the authenticator... */
+ status = (omapi_connection_copyin
+ (c, signature -> value -> u.buffer.value,
+ signature -> value -> u.buffer.len));
+ omapi_value_dereference (&signature, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Dectivate the authentication key on the connection. */
+ status = omapi_set_value_str (c, (omapi_object_t *)0,
+ "output-authenticator",
+ (omapi_typed_data_t *)0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ if (!omo) {
+ omapi_protocol_reference (&m -> protocol_object, p, MDL);
+ }
+ return ISC_R_SUCCESS;
+}
+
+
+isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ isc_result_t status;
+ omapi_protocol_object_t *p;
+ omapi_object_t *c;
+ omapi_message_object_t *m;
+ omapi_value_t *signature;
+ u_int16_t nlen;
+ u_int32_t vlen;
+ u_int32_t th;
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ unsigned long previous_outstanding = 0xDEADBEEF;
+ unsigned long connect_outstanding = 0xDEADBEEF;
+#endif
+
+ if (h -> type != omapi_type_protocol) {
+ /* XXX shouldn't happen. Put an assert here? */
+ return ISC_R_UNEXPECTED;
+ }
+ p = (omapi_protocol_object_t *)h;
+
+ if (!strcmp (name, "connect")) {
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ connect_outstanding = dmalloc_outstanding;
+#endif
+ /* Send the introductory message. */
+ status = omapi_protocol_send_intro
+ (h, OMAPI_PROTOCOL_VERSION,
+ sizeof (omapi_protocol_header_t));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (p -> outer, 1);
+ return status;
+ }
+ return ISC_R_SUCCESS;
+ }
+
+ /* Should only receive these when opening the initial authenticator. */
+ if (!strcmp (name, "status")) {
+ status = va_arg (ap, isc_result_t);
+ if (status != ISC_R_SUCCESS) {
+ omapi_signal_in (h -> inner, "status", status,
+ (omapi_object_t *)0);
+ omapi_disconnect (p -> outer, 1);
+ return status;
+ } else {
+ return omapi_signal_in (h -> inner, "ready");
+ }
+ }
+
+ /* If we get a disconnect, dump memory usage. */
+ if (!strcmp (name, "disconnect")) {
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ if (connect_outstanding != 0xDEADBEEF) {
+ log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
+ dmalloc_generation,
+ dmalloc_outstanding - previous_outstanding,
+ dmalloc_outstanding, dmalloc_longterm, " long-term");
+ }
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
+ dump_rc_history ();
+#endif
+ for (m = omapi_registered_messages; m; m = m -> next) {
+ if (m -> protocol_object == p) {
+ if (m -> object)
+ omapi_signal (m -> object, "disconnect");
+ }
+ }
+ }
+
+ /* Not a signal we recognize? */
+ if (strcmp (name, "ready")) {
+ if (p -> inner && p -> inner -> type -> signal_handler)
+ return (*(p -> inner -> type -> signal_handler)) (h,
+ name,
+ ap);
+ return ISC_R_NOTFOUND;
+ }
+
+ if (!p -> outer || p -> outer -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+ c = p -> outer;
+
+ /* We get here because we requested that we be woken up after
+ some number of bytes were read, and that number of bytes
+ has in fact been read. */
+ switch (p -> state) {
+ case omapi_protocol_intro_wait:
+ /* Get protocol version and header size in network
+ byte order. */
+ omapi_connection_get_uint32 (c, &p -> protocol_version);
+ omapi_connection_get_uint32 (c, &p -> header_size);
+
+ /* We currently only support the current protocol version. */
+ if (p -> protocol_version != OMAPI_PROTOCOL_VERSION) {
+ omapi_disconnect (c, 1);
+ return ISC_R_VERSIONMISMATCH;
+ }
+
+ if (p -> header_size < sizeof (omapi_protocol_header_t)) {
+ omapi_disconnect (c, 1);
+ return ISC_R_PROTOCOLERROR;
+ }
+
+ if (p -> default_auth) {
+ status = omapi_protocol_send_open
+ (h, (omapi_object_t *)0, "authenticator",
+ p -> default_auth -> a,
+ OMAPI_NOTIFY_PROTOCOL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ } else {
+ status = omapi_signal_in (h -> inner, "ready");
+ }
+
+ to_header_wait:
+ /* The next thing we're expecting is a message header. */
+ p -> state = omapi_protocol_header_wait;
+
+ /* Register a need for the number of bytes in a
+ header, and if we already have that many, process
+ them immediately. */
+ if ((omapi_connection_require (c, p -> header_size)) !=
+ ISC_R_SUCCESS)
+ break;
+ /* If we already have the data, fall through. */
+
+ case omapi_protocol_header_wait:
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ if (previous_outstanding != 0xDEADBEEF) {
+ log_info ("%s %ld: %ld new, %ld outstanding, %ld%s",
+ "generation", dmalloc_generation,
+ dmalloc_outstanding - previous_outstanding,
+ dmalloc_outstanding, dmalloc_longterm,
+ " long-term");
+#endif
+#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
+ dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
+ dump_rc_history ();
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ }
+ previous_outstanding = dmalloc_outstanding;
+#endif
+ status = omapi_message_new ((omapi_object_t **)&p -> message,
+ MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ p -> verify_result = ISC_R_SUCCESS;
+
+ /* Swap in the header... */
+ omapi_connection_get_uint32 (c, &p -> message -> authid);
+
+ /* Bind the authenticator to the message object. */
+ if (p -> message -> authid) {
+ status = (omapi_protocol_lookup_auth
+ (&p -> message -> id_object, h,
+ p -> message -> authid));
+ if (status != ISC_R_SUCCESS)
+ p -> verify_result = status;
+
+ /* Activate the authentication key. */
+ status = omapi_set_object_value
+ (c, (omapi_object_t *)0, "input-authenticator",
+ p -> message -> id_object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ omapi_connection_get_uint32 (c, &p -> message -> authlen);
+ omapi_connection_get_uint32 (c, &p -> message -> op);
+ omapi_connection_get_uint32 (c, &th);
+ p -> message -> h = th;
+ omapi_connection_get_uint32 (c, &p -> message -> id);
+ omapi_connection_get_uint32 (c, &p -> message -> rid);
+
+ /* If there was any extra header data, skip over it. */
+ if (p -> header_size > sizeof (omapi_protocol_header_t)) {
+ omapi_connection_copyout
+ (0, c, (p -> header_size -
+ sizeof (omapi_protocol_header_t)));
+ }
+
+ /* XXX must compute partial signature across the
+ XXX preceding bytes. Also, if authenticator
+ specifies encryption as well as signing, we may
+ have to decrypt the data on the way in. */
+
+ /* First we read in message-specific values, then object
+ values. */
+ p -> reading_message_values = 1;
+
+ need_name_length:
+ /* The next thing we're expecting is length of the
+ first name. */
+ p -> state = omapi_protocol_name_length_wait;
+
+ /* Wait for a 16-bit length. */
+ if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS)
+ break;
+ /* If it's already here, fall through. */
+
+ case omapi_protocol_name_length_wait:
+ omapi_connection_get_uint16 (c, &nlen);
+ /* A zero-length name means that we're done reading name+value
+ pairs. */
+ if (nlen == 0) {
+ /* If we've already read in the object, we are
+ done reading the message, but if we've just
+ finished reading in the values associated
+ with the message, we need to read the
+ object. */
+ if (p -> reading_message_values) {
+ p -> reading_message_values = 0;
+ goto need_name_length;
+ }
+
+ /* If the authenticator length is zero, there's no
+ signature to read in, so go straight to processing
+ the message. */
+ if (p -> message -> authlen == 0)
+ goto message_done;
+
+ /* The next thing we're expecting is the
+ message signature. */
+ p -> state = omapi_protocol_signature_wait;
+
+ /* Wait for the number of bytes specified for
+ the authenticator. If we already have it,
+ go read it in. */
+ if (omapi_connection_require
+ (c, p -> message -> authlen) == ISC_R_SUCCESS)
+ goto signature_wait;
+ break;
+ }
+
+ /* Allocate a buffer for the name. */
+ status = (omapi_data_string_new (&p -> name, nlen, MDL));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+ p -> state = omapi_protocol_name_wait;
+ if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS)
+ break;
+ /* If it's already here, fall through. */
+
+ case omapi_protocol_name_wait:
+ omapi_connection_copyout (p -> name -> value, c,
+ p -> name -> len);
+ /* Wait for a 32-bit length. */
+ p -> state = omapi_protocol_value_length_wait;
+ if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS)
+ break;
+ /* If it's already here, fall through. */
+
+ case omapi_protocol_value_length_wait:
+ omapi_connection_get_uint32 (c, &vlen);
+
+ /* Zero-length values are allowed - if we get one, we
+ don't have to read any data for the value - just
+ get the next one, if there is a next one. */
+ if (!vlen)
+ goto insert_new_value;
+
+ status = omapi_typed_data_new (MDL, &p -> value,
+ omapi_datatype_data,
+ vlen);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+
+ p -> state = omapi_protocol_value_wait;
+ if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS)
+ break;
+ /* If it's already here, fall through. */
+
+ case omapi_protocol_value_wait:
+ omapi_connection_copyout (p -> value -> u.buffer.value, c,
+ p -> value -> u.buffer.len);
+
+ insert_new_value:
+ if (p -> reading_message_values) {
+ status = (omapi_set_value
+ ((omapi_object_t *)p -> message,
+ p -> message -> id_object,
+ p -> name, p -> value));
+ } else {
+ if (!p -> message -> object) {
+ /* We need a generic object to hang off of the
+ incoming message. */
+ status = (omapi_generic_new
+ (&p -> message -> object, MDL));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+ status = (omapi_set_value
+ ((omapi_object_t *)p -> message -> object,
+ p -> message -> id_object,
+ p -> name, p -> value));
+ }
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ omapi_data_string_dereference (&p -> name, MDL);
+ if (p -> value)
+ omapi_typed_data_dereference (&p -> value, MDL);
+ goto need_name_length;
+
+ signature_wait:
+ case omapi_protocol_signature_wait:
+ if (p -> message -> id_object) {
+ /* Compute the signature of the message. */
+ signature = (omapi_value_t *)0;
+ status = omapi_get_value_str (c, (omapi_object_t *)0,
+ "input-signature",
+ &signature);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Disable the authentication key on the connection. */
+ status = omapi_set_value_str (c, (omapi_object_t *)0,
+ "input-authenticator",
+ (omapi_typed_data_t *)0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (&signature, MDL);
+ omapi_disconnect (c, 1);
+ return status;
+ }
+ }
+
+ /* Read the authenticator. */
+ status = omapi_typed_data_new (MDL,
+ &p -> message -> authenticator,
+ omapi_datatype_data,
+ p -> message -> authlen);
+
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (&signature, MDL);
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+ omapi_connection_copyout
+ (p -> message -> authenticator -> u.buffer.value, c,
+ p -> message -> authlen);
+
+ /* Verify the signature. */
+ if (p -> message -> id_object &&
+ ((signature -> value -> u.buffer.len !=
+ p -> message -> authlen) ||
+ (memcmp (signature -> value -> u.buffer.value,
+ p -> message -> authenticator -> u.buffer.value,
+ p -> message -> authlen) != 0))) {
+ /* Invalid signature. */
+ p -> verify_result = ISC_R_INVALIDKEY;
+ }
+
+ omapi_value_dereference (&signature, MDL);
+
+ /* Process the message. */
+ message_done:
+ if (p -> verify_result != ISC_R_SUCCESS) {
+ status = omapi_protocol_send_status
+ (h, (omapi_object_t *)0, p -> verify_result,
+ p -> message -> id, (char *)0);
+ } else {
+ status = omapi_message_process
+ ((omapi_object_t *)p -> message, h);
+ }
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+
+ omapi_message_dereference (&p -> message, MDL);
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
+ dmalloc_generation,
+ dmalloc_outstanding - previous_outstanding,
+ dmalloc_outstanding, dmalloc_longterm, " long-term");
+#endif
+#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
+ dmalloc_dump_outstanding ();
+#endif
+#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
+ dump_rc_history ();
+#endif
+#if defined (DEBUG_MEMORY_LEAKAGE)
+ previous_outstanding = 0xDEADBEEF;
+#endif
+ /* Now wait for the next message. */
+ goto to_header_wait;
+
+ default:
+ /* XXX should never get here. Assertion? */
+ break;
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_protocol_add_auth (omapi_object_t *po,
+ omapi_object_t *ao,
+ omapi_handle_t handle)
+{
+ omapi_protocol_object_t *p;
+ omapi_remote_auth_t *r;
+ isc_result_t status;
+
+ if (ao -> type != omapi_type_auth_key &&
+ (!ao -> inner || ao -> inner -> type != omapi_type_auth_key))
+ return ISC_R_INVALIDARG;
+
+ if (po -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)po;
+
+#ifdef DEBUG_PROTOCOL
+ log_debug ("omapi_protocol_add_auth(name=%s)",
+ ((omapi_auth_key_t *)ao) -> name);
+#endif
+
+ if (p -> verify_auth) {
+ status = (p -> verify_auth) (po, (omapi_auth_key_t *)ao);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ /* If omapi_protocol_connect() was called with a default
+ authenticator, p -> default_auth will already be set,
+ but p -> remote_auth_list will not yet be initialized. */
+ if (p -> default_auth && !p -> remote_auth_list) {
+ if (p -> default_auth -> a != ao) {
+ /* Something just went horribly wrong. */
+ omapi_disconnect (p -> outer, 1);
+ return ISC_R_UNEXPECTED;
+ }
+
+ p -> remote_auth_list = p -> default_auth;
+ p -> default_auth -> remote_handle = handle;
+
+ return omapi_signal_in (p -> inner, "ready");
+ }
+
+ r = dmalloc (sizeof(*r), MDL);
+ if (!r)
+ return ISC_R_NOMEMORY;
+
+ status = omapi_object_reference (&r -> a, ao, MDL);
+ if (status != ISC_R_SUCCESS) {
+ dfree (r, MDL);
+ return status;
+ }
+
+ r -> remote_handle = handle;
+ r -> next = p -> remote_auth_list;
+ p -> remote_auth_list = r;
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_protocol_lookup_auth (omapi_object_t **a,
+ omapi_object_t *po,
+ omapi_handle_t handle)
+{
+ omapi_protocol_object_t *p;
+ omapi_remote_auth_t *r;
+
+ if (po -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)po;
+
+ for (r = p -> remote_auth_list; r; r = r -> next)
+ if (r -> remote_handle == handle)
+ return omapi_object_reference (a, r -> a, MDL);
+
+ return ISC_R_KEY_UNKNOWN;
+}
+
+isc_result_t omapi_protocol_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_protocol_object_t *p;
+ omapi_remote_auth_t *r;
+
+ if (h -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)h;
+
+ if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
+ if (value -> type != omapi_datatype_object)
+ return ISC_R_INVALIDARG;
+
+ if (!value || !value -> u.object) {
+ p -> default_auth = (omapi_remote_auth_t *)0;
+ } else {
+ for (r = p -> remote_auth_list; r; r = r -> next)
+ if (r -> a == value -> u.object)
+ break;
+
+ if (!r)
+ return ISC_R_KEY_UNKNOWN;
+
+ p -> default_auth = r;
+ }
+
+ return ISC_R_SUCCESS;
+ }
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_protocol_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_protocol_object_t *p;
+
+ if (h -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)h;
+
+ if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
+ if (!p -> default_auth)
+ return ISC_R_NOTFOUND;
+
+ return omapi_make_object_value (value, name,
+ p -> default_auth -> a, MDL);
+ }
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_protocol_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_protocol_object_t *p;
+ if (h -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+ p = (omapi_protocol_object_t *)h;
+ if (p -> message)
+ omapi_message_dereference (&p -> message, file, line);
+
+ /* This will happen if: 1) A default authenticator is supplied to
+ omapi_protocol_connect(), and 2) something goes wrong before
+ the authenticator can be opened. */
+ if (p -> default_auth && !p -> remote_auth_list)
+ dfree (p -> default_auth, file, line);
+
+ while (p -> remote_auth_list) {
+ omapi_remote_auth_t *r = p -> remote_auth_list -> next;
+ p -> remote_auth_list = r;
+ if (r) {
+ omapi_object_dereference (&r -> a, file, line);
+ dfree (r, file, line);
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_protocol_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *p)
+{
+ int i;
+
+ if (p -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+
+ if (p -> inner && p -> inner -> type -> stuff_values)
+ return (*(p -> inner -> type -> stuff_values)) (c, id,
+ p -> inner);
+ return ISC_R_SUCCESS;
+}
+
+/* Returns a boolean indicating whether this protocol requires that
+ messages be authenticated or not. */
+
+isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h)
+{
+ if (h -> type != omapi_type_protocol)
+ return isc_boolean_false;
+ if (((omapi_protocol_object_t *)h) -> insecure)
+ return isc_boolean_false;
+ else
+ return isc_boolean_true;
+}
+
+/* Sets the address and authenticator verification callbacks. The handle
+ is to a listener object, not a protocol object. */
+
+isc_result_t omapi_protocol_configure_security (omapi_object_t *h,
+ isc_result_t (*verify_addr)
+ (omapi_object_t *,
+ omapi_addr_t *),
+ isc_result_t (*verify_auth)
+ (omapi_object_t *,
+ omapi_auth_key_t *))
+{
+ omapi_protocol_listener_object_t *l;
+
+ if (h -> outer && h -> outer -> type == omapi_type_protocol_listener)
+ h = h -> outer;
+
+ if (h -> type != omapi_type_protocol_listener)
+ return ISC_R_INVALIDARG;
+ l = (omapi_protocol_listener_object_t *)h;
+
+ l -> verify_auth = verify_auth;
+ l -> insecure = 0;
+
+ return omapi_listener_configure_security (h -> outer, verify_addr);
+}
+
+
+/* Set up a listener for the omapi protocol. The handle stored points to
+ a listener object, not a protocol object. */
+
+isc_result_t omapi_protocol_listen (omapi_object_t *h,
+ unsigned port,
+ int max)
+{
+ isc_result_t status;
+ omapi_protocol_listener_object_t *obj;
+
+ obj = (omapi_protocol_listener_object_t *)0;
+ status = omapi_protocol_listener_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_reference (&h -> outer,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_protocol_listener_dereference (&obj, MDL);
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, h, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_protocol_listener_dereference (&obj, MDL);
+ return status;
+ }
+
+ /* What a terrible default. */
+ obj -> insecure = 1;
+
+ status = omapi_listen ((omapi_object_t *)obj, port, max);
+ omapi_protocol_listener_dereference (&obj, MDL);
+ return status;
+}
+
+/* Signal handler for protocol listener - if we get a connect signal,
+ create a new protocol connection, otherwise pass the signal down. */
+
+isc_result_t omapi_protocol_listener_signal (omapi_object_t *o,
+ const char *name, va_list ap)
+{
+ isc_result_t status;
+ omapi_object_t *c;
+ omapi_protocol_object_t *obj;
+ omapi_protocol_listener_object_t *p;
+
+ if (!o || o -> type != omapi_type_protocol_listener)
+ return ISC_R_INVALIDARG;
+ p = (omapi_protocol_listener_object_t *)o;
+
+ /* Not a signal we recognize? */
+ if (strcmp (name, "connect")) {
+ if (p -> inner && p -> inner -> type -> signal_handler)
+ return (*(p -> inner -> type -> signal_handler))
+ (p -> inner, name, ap);
+ return ISC_R_NOTFOUND;
+ }
+
+ c = va_arg (ap, omapi_object_t *);
+ if (!c || c -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+
+ obj = (omapi_protocol_object_t *)0;
+ status = omapi_protocol_allocate (&obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ obj -> verify_auth = p -> verify_auth;
+ obj -> insecure = p -> insecure;
+
+ status = omapi_object_reference (&obj -> outer, c, MDL);
+ if (status != ISC_R_SUCCESS) {
+ lose:
+ omapi_protocol_dereference (&obj, MDL);
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ status = omapi_object_reference (&c -> inner,
+ (omapi_object_t *)obj, MDL);
+ if (status != ISC_R_SUCCESS)
+ goto lose;
+
+ /* Send the introductory message. */
+ status = omapi_protocol_send_intro ((omapi_object_t *)obj,
+ OMAPI_PROTOCOL_VERSION,
+ sizeof (omapi_protocol_header_t));
+ if (status != ISC_R_SUCCESS)
+ goto lose;
+
+ omapi_protocol_dereference (&obj, MDL);
+ return status;
+}
+
+isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ if (h -> type != omapi_type_protocol_listener)
+ return ISC_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> set_value)
+ return (*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ if (h -> type != omapi_type_protocol_listener)
+ return ISC_R_INVALIDARG;
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ if (h -> type != omapi_type_protocol_listener)
+ return ISC_R_INVALIDARG;
+ return ISC_R_SUCCESS;
+}
+
+/* Write all the published values associated with the object through the
+ specified connection. */
+
+isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *p)
+{
+ int i;
+
+ if (p -> type != omapi_type_protocol_listener)
+ return ISC_R_INVALIDARG;
+
+ if (p -> inner && p -> inner -> type -> stuff_values)
+ return (*(p -> inner -> type -> stuff_values)) (c, id,
+ p -> inner);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_protocol_send_status (omapi_object_t *po,
+ omapi_object_t *id,
+ isc_result_t waitstatus,
+ unsigned rid, const char *msg)
+{
+ isc_result_t status;
+ omapi_message_object_t *message = (omapi_message_object_t *)0;
+ omapi_object_t *mo;
+
+ if (po -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+
+ status = omapi_message_new ((omapi_object_t **)&message, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ mo = (omapi_object_t *)message;
+
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "op", OMAPI_OP_STATUS);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "rid", (int)rid);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "result", (int)waitstatus);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ /* If a message has been provided, send it. */
+ if (msg) {
+ status = omapi_set_string_value (mo, (omapi_object_t *)0,
+ "message", msg);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+ }
+
+ status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
+ omapi_message_dereference (&message, MDL);
+ return status;
+}
+
+/* The OMAPI_NOTIFY_PROTOCOL flag will cause the notify-object for the
+ message to be set to the protocol object. This is used when opening
+ the default authenticator. */
+
+isc_result_t omapi_protocol_send_open (omapi_object_t *po,
+ omapi_object_t *id,
+ const char *type,
+ omapi_object_t *object,
+ unsigned flags)
+{
+ isc_result_t status;
+ omapi_message_object_t *message = (omapi_message_object_t *)0;
+ omapi_object_t *mo;
+
+ if (po -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+
+ status = omapi_message_new ((omapi_object_t **)&message, MDL);
+ mo = (omapi_object_t *)message;
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "op", OMAPI_OP_OPEN);
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_set_object_value (mo, (omapi_object_t *)0,
+ "object", object);
+
+ if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS))
+ status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
+ "create", 1);
+
+ if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS))
+ status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
+ "update", 1);
+
+ if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS))
+ status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
+ "exclusive", 1);
+
+ if ((flags & OMAPI_NOTIFY_PROTOCOL) && (status == ISC_R_SUCCESS))
+ status = omapi_set_object_value (mo, (omapi_object_t *)0,
+ "notify-object", po);
+
+ if (type && (status == ISC_R_SUCCESS))
+ status = omapi_set_string_value (mo, (omapi_object_t *)0,
+ "type", type);
+
+ if (status == ISC_R_SUCCESS)
+ status = omapi_message_register (mo);
+
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_protocol_send_message (po, id, mo,
+ (omapi_object_t *)0);
+ if (status != ISC_R_SUCCESS)
+ omapi_message_unregister (mo);
+ }
+
+ if (message)
+ omapi_message_dereference (&message, MDL);
+
+ return status;
+}
+
+isc_result_t omapi_protocol_send_update (omapi_object_t *po,
+ omapi_object_t *id,
+ unsigned rid,
+ omapi_object_t *object)
+{
+ isc_result_t status;
+ omapi_message_object_t *message = (omapi_message_object_t *)0;
+ omapi_object_t *mo;
+
+ if (po -> type != omapi_type_protocol)
+ return ISC_R_INVALIDARG;
+
+ status = omapi_message_new ((omapi_object_t **)&message, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ mo = (omapi_object_t *)message;
+
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "op", OMAPI_OP_UPDATE);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ if (rid) {
+ omapi_handle_t handle;
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "rid", (int)rid);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ status = omapi_object_handle (&handle, object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+ status = omapi_set_int_value (mo, (omapi_object_t *)0,
+ "handle", (int)handle);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+ }
+
+ status = omapi_set_object_value (mo, (omapi_object_t *)0,
+ "object", object);
+ if (status != ISC_R_SUCCESS) {
+ omapi_message_dereference (&message, MDL);
+ return status;
+ }
+
+ status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
+ omapi_message_dereference (&message, MDL);
+ return status;
+}
diff --git a/contrib/isc-dhcp/omapip/result.c b/contrib/isc-dhcp/omapip/result.c
new file mode 100644
index 000000000000..8e6695ef9d45
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/result.c
@@ -0,0 +1,125 @@
+/* result.c
+
+ Cheap knock-off of libisc result table code. This is just a place-holder
+ until the actual libisc merge. */
+
+/*
+ * Copyright (c) 1999-2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+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 */
+ "task is done", /* 16 */
+ "lock busy", /* 17 */
+ "already exists", /* 18 */
+ "ran out of space", /* 19 */
+ "operation canceled", /* 20 */
+ "sending events is not allowed", /* 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 */
+ "host unknown", /* 36 */
+ "protocol version mismatch", /* 37 */
+ "protocol error", /* 38 */
+ "invalid argument", /* 39 */
+ "not connected", /* 40 */
+ "data not yet available", /* 41 */
+ "object unchanged", /* 42 */
+ "more than one object matches key", /* 43 */
+ "key conflict", /* 44 */
+ "parse error(s) occurred", /* 45 */
+ "no key specified", /* 46 */
+ "zone TSIG key not known", /* 47 */
+ "invalid TSIG key", /* 48 */
+ "operation in progress", /* 49 */
+ "DNS format error", /* 50 */
+ "DNS server failed", /* 51 */
+ "no such domain", /* 52 */
+ "not implemented", /* 53 */
+ "refused", /* 54 */
+ "domain already exists", /* 55 */
+ "RRset already exists", /* 56 */
+ "no such RRset", /* 57 */
+ "not authorized", /* 58 */
+ "not a zone", /* 59 */
+ "bad DNS signature", /* 60 */
+ "bad DNS key", /* 61 */
+ "clock skew too great", /* 62 */
+ "no root zone", /* 63 */
+ "destination address required", /* 64 */
+ "cross-zone update", /* 65 */
+ "no TSIG signature", /* 66 */
+ "not equal", /* 67 */
+ "connection reset by peer", /* 68 */
+ "unknown attribute" /* 69 */
+};
+
+const char *isc_result_totext (isc_result_t result)
+{
+ if (result >= ISC_R_SUCCESS && result < ISC_R_NRESULTS)
+ return text [result];
+ return "unknown error.";
+}
diff --git a/contrib/isc-dhcp/omapip/support.c b/contrib/isc-dhcp/omapip/support.c
new file mode 100644
index 000000000000..1fb98032aa81
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/support.c
@@ -0,0 +1,872 @@
+/* support.c
+
+ Subroutines providing general support for objects. */
+
+/*
+ * Copyright (c) 1999-2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+omapi_object_type_t *omapi_type_connection;
+omapi_object_type_t *omapi_type_listener;
+omapi_object_type_t *omapi_type_io_object;
+omapi_object_type_t *omapi_type_datagram;
+omapi_object_type_t *omapi_type_generic;
+omapi_object_type_t *omapi_type_protocol;
+omapi_object_type_t *omapi_type_protocol_listener;
+omapi_object_type_t *omapi_type_waiter;
+omapi_object_type_t *omapi_type_remote;
+omapi_object_type_t *omapi_type_message;
+omapi_object_type_t *omapi_type_auth_key;
+
+omapi_object_type_t *omapi_object_types;
+int omapi_object_type_count;
+static int ot_max;
+
+#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+void omapi_type_relinquish ()
+{
+ omapi_object_type_t *t, *n;
+
+ for (t = omapi_object_types; t; t = n) {
+ n = t -> next;
+ dfree (t, MDL);
+ }
+ omapi_object_types = (omapi_object_type_t *)0;
+}
+#endif
+
+isc_result_t omapi_init (void)
+{
+ isc_result_t status;
+
+ dst_init();
+
+ /* Register all the standard object types... */
+ status = omapi_object_type_register (&omapi_type_connection,
+ "connection",
+ omapi_connection_set_value,
+ omapi_connection_get_value,
+ omapi_connection_destroy,
+ omapi_connection_signal_handler,
+ omapi_connection_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof
+ (omapi_connection_object_t), 0,
+ RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_listener,
+ "listener",
+ omapi_listener_set_value,
+ omapi_listener_get_value,
+ omapi_listener_destroy,
+ omapi_listener_signal_handler,
+ omapi_listener_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_listener_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_io_object,
+ "io",
+ omapi_io_set_value,
+ omapi_io_get_value,
+ omapi_io_destroy,
+ omapi_io_signal_handler,
+ omapi_io_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_io_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_generic,
+ "generic",
+ omapi_generic_set_value,
+ omapi_generic_get_value,
+ omapi_generic_destroy,
+ omapi_generic_signal_handler,
+ omapi_generic_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_generic_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_protocol,
+ "protocol",
+ omapi_protocol_set_value,
+ omapi_protocol_get_value,
+ omapi_protocol_destroy,
+ omapi_protocol_signal_handler,
+ omapi_protocol_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_protocol_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = (omapi_object_type_register
+ (&omapi_type_protocol_listener, "protocol-listener",
+ omapi_protocol_listener_set_value,
+ omapi_protocol_listener_get_value,
+ omapi_protocol_listener_destroy,
+ omapi_protocol_listener_signal,
+ omapi_protocol_listener_stuff,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_protocol_listener_object_t), 0, RC_MISC));
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_message,
+ "message",
+ omapi_message_set_value,
+ omapi_message_get_value,
+ omapi_message_destroy,
+ omapi_message_signal_handler,
+ omapi_message_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_message_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_waiter,
+ "waiter",
+ 0,
+ 0,
+ 0,
+ omapi_waiter_signal_handler, 0,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (omapi_waiter_object_t),
+ 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_auth_key,
+ "authenticator",
+ 0,
+ omapi_auth_key_get_value,
+ omapi_auth_key_destroy,
+ 0,
+ omapi_auth_key_stuff_values,
+ omapi_auth_key_lookup,
+ 0, 0, 0, 0, 0,
+ sizeof (omapi_auth_key_t), 0,
+ RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+#if defined (TRACING)
+ omapi_listener_trace_setup ();
+ omapi_connection_trace_setup ();
+ omapi_buffer_trace_setup ();
+ trace_mr_init ();
+#endif
+
+ /* This seems silly, but leave it. */
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_object_type_register (omapi_object_type_t **type,
+ const char *name,
+ isc_result_t (*set_value)
+ (omapi_object_t *,
+ omapi_object_t *,
+ omapi_data_string_t *,
+ omapi_typed_data_t *),
+ isc_result_t (*get_value)
+ (omapi_object_t *,
+ omapi_object_t *,
+ omapi_data_string_t *,
+ omapi_value_t **),
+ isc_result_t (*destroy)
+ (omapi_object_t *,
+ const char *, int),
+ isc_result_t (*signal_handler)
+ (omapi_object_t *,
+ const char *, va_list),
+ isc_result_t (*stuff_values)
+ (omapi_object_t *,
+ omapi_object_t *,
+ omapi_object_t *),
+ isc_result_t (*lookup)
+ (omapi_object_t **,
+ omapi_object_t *,
+ omapi_object_t *),
+ isc_result_t (*create)
+ (omapi_object_t **,
+ omapi_object_t *),
+ isc_result_t (*remove)
+ (omapi_object_t *,
+ omapi_object_t *),
+ isc_result_t (*freer)
+ (omapi_object_t *,
+ const char *, int),
+ isc_result_t (*allocator)
+ (omapi_object_t **,
+ const char *, int),
+ isc_result_t (*sizer) (size_t),
+ size_t size,
+ isc_result_t (*initialize)
+ (omapi_object_t *,
+ const char *, int),
+ int rc_flag)
+{
+ omapi_object_type_t *t;
+
+ t = dmalloc (sizeof *t, MDL);
+ if (!t)
+ return ISC_R_NOMEMORY;
+ memset (t, 0, sizeof *t);
+
+ t -> name = name;
+ t -> set_value = set_value;
+ t -> get_value = get_value;
+ t -> destroy = destroy;
+ t -> signal_handler = signal_handler;
+ t -> stuff_values = stuff_values;
+ t -> lookup = lookup;
+ t -> create = create;
+ t -> remove = remove;
+ t -> next = omapi_object_types;
+ t -> sizer = sizer;
+ t -> size = size;
+ t -> freer = freer;
+ t -> allocator = allocator;
+ t -> initialize = initialize;
+ t -> rc_flag = rc_flag;
+ omapi_object_types = t;
+ if (type)
+ *type = t;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_signal (omapi_object_t *handle, const char *name, ...)
+{
+ va_list ap;
+ omapi_object_t *outer;
+ isc_result_t status;
+
+ va_start (ap, name);
+ for (outer = handle; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> signal_handler)
+ status = (*(outer -> type -> signal_handler)) (outer,
+ name, ap);
+ else
+ status = ISC_R_NOTFOUND;
+ va_end (ap);
+ return status;
+}
+
+isc_result_t omapi_signal_in (omapi_object_t *handle, const char *name, ...)
+{
+ va_list ap;
+ omapi_object_t *outer;
+ isc_result_t status;
+
+ if (!handle)
+ return ISC_R_NOTFOUND;
+ va_start (ap, name);
+
+ if (handle -> type -> signal_handler)
+ status = (*(handle -> type -> signal_handler)) (handle,
+ name, ap);
+ else
+ status = ISC_R_NOTFOUND;
+ va_end (ap);
+ return status;
+}
+
+isc_result_t omapi_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_object_t *outer;
+ isc_result_t status;
+
+#if defined (DEBUG)
+ if (!value) {
+ log_info ("omapi_set_value (%.*s, NULL)",
+ (int)name -> len, name -> value);
+ } else if (value -> type == omapi_datatype_int) {
+ log_info ("omapi_set_value (%.*s, %ld)",
+ (int)name -> len, name -> value,
+ (long)value -> u.integer);
+ } else if (value -> type == omapi_datatype_string) {
+ log_info ("omapi_set_value (%.*s, %.*s)",
+ (int)name -> len, name -> value,
+ (int)value -> u.buffer.len, value -> u.buffer.value);
+ } else if (value -> type == omapi_datatype_data) {
+ log_info ("omapi_set_value (%.*s, %ld %lx)",
+ (int)name -> len, name -> value,
+ (long)value -> u.buffer.len,
+ (unsigned long)value -> u.buffer.value);
+ } else if (value -> type == omapi_datatype_object) {
+ log_info ("omapi_set_value (%.*s, %s)",
+ (int)name -> len, name -> value,
+ value -> u.object
+ ? (value -> u.object -> type
+ ? value -> u.object -> type -> name
+ : "(unknown object)")
+ : "(unknown object)");
+ }
+#endif
+
+ for (outer = h; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> set_value)
+ status = (*(outer -> type -> set_value)) (outer,
+ id, name, value);
+ else
+ status = ISC_R_NOTFOUND;
+#if defined (DEBUG)
+ log_info (" ==> %s", isc_result_totext (status));
+#endif
+ return status;
+}
+
+isc_result_t omapi_set_value_str (omapi_object_t *h,
+ omapi_object_t *id,
+ const char *name,
+ omapi_typed_data_t *value)
+{
+ omapi_object_t *outer;
+ omapi_data_string_t *nds;
+ isc_result_t status;
+
+ nds = (omapi_data_string_t *)0;
+ status = omapi_data_string_new (&nds, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (nds -> value, name, strlen (name));
+
+ status = omapi_set_value (h, id, nds, value);
+ omapi_data_string_dereference (&nds, MDL);
+ return status;
+}
+
+isc_result_t omapi_set_boolean_value (omapi_object_t *h, omapi_object_t *id,
+ const char *name, int value)
+{
+ isc_result_t status;
+ omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
+ omapi_data_string_t *n = (omapi_data_string_t *)0;
+ int len;
+ int ip;
+
+ status = omapi_data_string_new (&n, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (n -> value, name, strlen (name));
+
+ status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_data_string_dereference (&n, MDL);
+ return status;
+ }
+
+ status = omapi_set_value (h, id, n, tv);
+ omapi_data_string_dereference (&n, MDL);
+ omapi_typed_data_dereference (&tv, MDL);
+ return status;
+}
+
+isc_result_t omapi_set_int_value (omapi_object_t *h, omapi_object_t *id,
+ const char *name, int value)
+{
+ isc_result_t status;
+ omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
+ omapi_data_string_t *n = (omapi_data_string_t *)0;
+ int len;
+ int ip;
+
+ status = omapi_data_string_new (&n, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (n -> value, name, strlen (name));
+
+ status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_data_string_dereference (&n, MDL);
+ return status;
+ }
+
+ status = omapi_set_value (h, id, n, tv);
+ omapi_data_string_dereference (&n, MDL);
+ omapi_typed_data_dereference (&tv, MDL);
+ return status;
+}
+
+isc_result_t omapi_set_object_value (omapi_object_t *h, omapi_object_t *id,
+ const char *name, omapi_object_t *value)
+{
+ isc_result_t status;
+ omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
+ omapi_data_string_t *n = (omapi_data_string_t *)0;
+ int len;
+ int ip;
+
+ status = omapi_data_string_new (&n, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (n -> value, name, strlen (name));
+
+ status = omapi_typed_data_new (MDL, &tv, omapi_datatype_object, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_data_string_dereference (&n, MDL);
+ return status;
+ }
+
+ status = omapi_set_value (h, id, n, tv);
+ omapi_data_string_dereference (&n, MDL);
+ omapi_typed_data_dereference (&tv, MDL);
+ return status;
+}
+
+isc_result_t omapi_set_string_value (omapi_object_t *h, omapi_object_t *id,
+ const char *name, const char *value)
+{
+ isc_result_t status;
+ omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
+ omapi_data_string_t *n = (omapi_data_string_t *)0;
+ int len;
+ int ip;
+
+ status = omapi_data_string_new (&n, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (n -> value, name, strlen (name));
+
+ status = omapi_typed_data_new (MDL, &tv, omapi_datatype_string, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_data_string_dereference (&n, MDL);
+ return status;
+ }
+
+ status = omapi_set_value (h, id, n, tv);
+ omapi_data_string_dereference (&n, MDL);
+ omapi_typed_data_dereference (&tv, MDL);
+ return status;
+}
+
+isc_result_t omapi_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ omapi_object_t *outer;
+
+ for (outer = h; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> get_value)
+ return (*(outer -> type -> get_value)) (outer,
+ id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_get_value_str (omapi_object_t *h,
+ omapi_object_t *id,
+ const char *name,
+ omapi_value_t **value)
+{
+ omapi_object_t *outer;
+ omapi_data_string_t *nds;
+ isc_result_t status;
+
+ nds = (omapi_data_string_t *)0;
+ status = omapi_data_string_new (&nds, strlen (name), MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (nds -> value, name, strlen (name));
+
+ for (outer = h; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> get_value)
+ status = (*(outer -> type -> get_value)) (outer,
+ id, nds, value);
+ else
+ status = ISC_R_NOTFOUND;
+ omapi_data_string_dereference (&nds, MDL);
+ return status;
+}
+
+isc_result_t omapi_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *o)
+{
+ omapi_object_t *outer;
+
+ for (outer = o; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> stuff_values)
+ return (*(outer -> type -> stuff_values)) (c, id, outer);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_object_create (omapi_object_t **obj, omapi_object_t *id,
+ omapi_object_type_t *type)
+{
+ if (!type -> create)
+ return ISC_R_NOTIMPLEMENTED;
+ return (*(type -> create)) (obj, id);
+}
+
+isc_result_t omapi_object_update (omapi_object_t *obj, omapi_object_t *id,
+ omapi_object_t *src, omapi_handle_t handle)
+{
+ omapi_generic_object_t *gsrc;
+ isc_result_t status;
+ int i;
+
+ if (!src)
+ return ISC_R_INVALIDARG;
+ if (src -> type != omapi_type_generic)
+ return ISC_R_NOTIMPLEMENTED;
+ gsrc = (omapi_generic_object_t *)src;
+ for (i = 0; i < gsrc -> nvalues; i++) {
+ status = omapi_set_value (obj, id,
+ gsrc -> values [i] -> name,
+ gsrc -> values [i] -> value);
+ if (status != ISC_R_SUCCESS && status != ISC_R_UNCHANGED)
+ return status;
+ }
+ if (handle)
+ omapi_set_int_value (obj, id, "remote-handle", (int)handle);
+ status = omapi_signal (obj, "updated");
+ if (status != ISC_R_NOTFOUND)
+ return status;
+ return ISC_R_SUCCESS;
+}
+
+int omapi_data_string_cmp (omapi_data_string_t *s1, omapi_data_string_t *s2)
+{
+ unsigned len;
+ int rv;
+
+ if (s1 -> len > s2 -> len)
+ len = s2 -> len;
+ else
+ len = s1 -> len;
+ rv = memcmp (s1 -> value, s2 -> value, len);
+ if (rv)
+ return rv;
+ if (s1 -> len > s2 -> len)
+ return 1;
+ else if (s1 -> len < s2 -> len)
+ return -1;
+ return 0;
+}
+
+int omapi_ds_strcmp (omapi_data_string_t *s1, const char *s2)
+{
+ unsigned len, slen;
+ int rv;
+
+ slen = strlen (s2);
+ if (slen > s1 -> len)
+ len = s1 -> len;
+ else
+ len = slen;
+ rv = memcmp (s1 -> value, s2, len);
+ if (rv)
+ return rv;
+ if (s1 -> len > slen)
+ return 1;
+ else if (s1 -> len < slen)
+ return -1;
+ return 0;
+}
+
+int omapi_td_strcmp (omapi_typed_data_t *s1, const char *s2)
+{
+ unsigned len, slen;
+ int rv;
+
+ /* If the data type is not compatible, never equal. */
+ if (s1 -> type != omapi_datatype_data &&
+ s1 -> type != omapi_datatype_string)
+ return -1;
+
+ slen = strlen (s2);
+ if (slen > s1 -> u.buffer.len)
+ len = s1 -> u.buffer.len;
+ else
+ len = slen;
+ rv = memcmp (s1 -> u.buffer.value, s2, len);
+ if (rv)
+ return rv;
+ if (s1 -> u.buffer.len > slen)
+ return 1;
+ else if (s1 -> u.buffer.len < slen)
+ return -1;
+ return 0;
+}
+
+int omapi_td_strcasecmp (omapi_typed_data_t *s1, const char *s2)
+{
+ unsigned len, slen;
+ int rv;
+
+ /* If the data type is not compatible, never equal. */
+ if (s1 -> type != omapi_datatype_data &&
+ s1 -> type != omapi_datatype_string)
+ return -1;
+
+ slen = strlen (s2);
+ if (slen > s1 -> u.buffer.len)
+ len = s1 -> u.buffer.len;
+ else
+ len = slen;
+ rv = casecmp (s1 -> u.buffer.value, s2, len);
+ if (rv)
+ return rv;
+ if (s1 -> u.buffer.len > slen)
+ return 1;
+ else if (s1 -> u.buffer.len < slen)
+ return -1;
+ return 0;
+}
+
+isc_result_t omapi_make_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_reference (&(*vp) -> value,
+ value, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_const_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ const unsigned char *value,
+ unsigned len,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_data, len);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ memcpy ((*vp) -> value -> u.buffer.value, value, len);
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_int_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ int value, const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_int, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_uint_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ unsigned int value,
+ const char *file, int line)
+{
+ return omapi_make_int_value (vp, name, (int)value, file, line);
+}
+
+isc_result_t omapi_make_object_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ omapi_object_t *value,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+
+ if (value) {
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_object, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_handle_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ omapi_object_t *value,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_int);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ status = (omapi_object_handle
+ ((omapi_handle_t *)&(*vp) -> value -> u.integer,
+ value));
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_string_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ const char *value,
+ const char *file, int line)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, file, line);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name,
+ name, file, line);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_new (file, line, &(*vp) -> value,
+ omapi_datatype_string, value);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, file, line);
+ return status;
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_get_int_value (unsigned long *v, omapi_typed_data_t *t)
+{
+ u_int32_t rv;
+
+ if (t -> type == omapi_datatype_int) {
+ *v = t -> u.integer;
+ return ISC_R_SUCCESS;
+ } else if (t -> type == omapi_datatype_string ||
+ t -> type == omapi_datatype_data) {
+ if (t -> u.buffer.len != sizeof (rv))
+ return ISC_R_INVALIDARG;
+ memcpy (&rv, t -> u.buffer.value, sizeof rv);
+ *v = ntohl (rv);
+ return ISC_R_SUCCESS;
+ }
+ return ISC_R_INVALIDARG;
+}
diff --git a/contrib/isc-dhcp/omapip/test.c b/contrib/isc-dhcp/omapip/test.c
new file mode 100644
index 000000000000..249099e69029
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/test.c
@@ -0,0 +1,108 @@
+/* test.c
+
+ Test code for omapip... */
+
+/*
+ * Copyright (c) 1999-2000 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <isc-dhcp/result.h>
+#include <sys/time.h>
+#include <omapip/omapip.h>
+
+int main (int argc, char **argv)
+{
+ omapi_object_t *listener = (omapi_object_t*)0;
+ omapi_object_t *connection = (omapi_object_t*)0;
+ isc_result_t status;
+
+ omapi_init ();
+
+ if (argc > 1 && !strcmp (argv [1], "listen")) {
+ if (argc < 3) {
+ fprintf (stderr, "Usage: test listen port\n");
+ exit (1);
+ }
+ status = omapi_generic_new (&listener, MDL);
+ if (status != ISC_R_SUCCESS) {
+ fprintf (stderr, "omapi_generic_new: %s\n",
+ isc_result_totext (status));
+ exit (1);
+ }
+ status = omapi_protocol_listen (listener,
+ (unsigned)atoi (argv [2]), 1);
+ if (status != ISC_R_SUCCESS) {
+ fprintf (stderr, "omapi_listen: %s\n",
+ isc_result_totext (status));
+ exit (1);
+ }
+ omapi_dispatch (0);
+ } else if (argc > 1 && !strcmp (argv [1], "connect")) {
+ if (argc < 4) {
+ fprintf (stderr, "Usage: test listen address port\n");
+ exit (1);
+ }
+ status = omapi_generic_new (&connection, MDL);
+ if (status != ISC_R_SUCCESS) {
+ fprintf (stderr, "omapi_generic_new: %s\n",
+ isc_result_totext (status));
+ exit (1);
+ }
+ status = omapi_protocol_connect (connection,
+ argv [2],
+ (unsigned)atoi (argv [3]), 0);
+ fprintf (stderr, "connect: %s\n", isc_result_totext (status));
+ if (status != ISC_R_SUCCESS)
+ exit (1);
+ status = omapi_wait_for_completion (connection, 0);
+ fprintf (stderr, "completion: %s\n",
+ isc_result_totext (status));
+ if (status != ISC_R_SUCCESS)
+ exit (1);
+ /* ... */
+ } else {
+ fprintf (stderr, "Usage: test [listen | connect] ...\n");
+ exit (1);
+ }
+
+ return 0;
+}
diff --git a/contrib/isc-dhcp/omapip/toisc.c b/contrib/isc-dhcp/omapip/toisc.c
new file mode 100644
index 000000000000..a30dcffd3a1e
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/toisc.c
@@ -0,0 +1,324 @@
+/* toisc.c
+
+ Convert non-ISC result codes to ISC result codes. */
+
+/*
+ * Copyright (c) 2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+isc_result_t ns_rcode_to_isc (int nsr)
+{
+ switch (nsr) {
+ case ns_r_noerror:
+ return ISC_R_SUCCESS;
+
+ case ns_r_formerr:
+ return ISC_R_FORMERR;
+
+ case ns_r_servfail:
+ return ISC_R_SERVFAIL;
+
+ case ns_r_nxdomain:
+ return ISC_R_NXDOMAIN;
+
+ case ns_r_notimpl:
+ return ISC_R_NOTIMPL;
+
+ case ns_r_refused:
+ return ISC_R_REFUSED;
+
+ case ns_r_yxdomain:
+ return ISC_R_YXDOMAIN;
+
+ case ns_r_yxrrset:
+ return ISC_R_YXRRSET;
+
+ case ns_r_nxrrset:
+ return ISC_R_NXRRSET;
+
+ case ns_r_notauth:
+ return ISC_R_NOTAUTH;
+
+ case ns_r_notzone:
+ return ISC_R_NOTZONE;
+
+ case ns_r_badsig:
+ return ISC_R_BADSIG;
+
+ case ns_r_badkey:
+ return ISC_R_BADKEY;
+
+ case ns_r_badtime:
+ return ISC_R_BADTIME;
+
+ default:
+ ;
+ }
+ return ISC_R_UNEXPECTED;
+}
+
+isc_result_t uerr2isc (int err)
+{
+ switch (err) {
+ case EPERM:
+ return ISC_R_NOPERM;
+
+ case ENOENT:
+ return ISC_R_NOTFOUND;
+
+ case ESRCH:
+ return ISC_R_NOTFOUND;
+
+ case EIO:
+ return ISC_R_IOERROR;
+
+ case ENXIO:
+ return ISC_R_NOTFOUND;
+
+ case E2BIG:
+ return ISC_R_NOSPACE;
+
+ case ENOEXEC:
+ return ISC_R_FORMERR;
+
+ case ECHILD:
+ return ISC_R_NOTFOUND;
+
+ case ENOMEM:
+ return ISC_R_NOMEMORY;
+
+ case EACCES:
+ return ISC_R_NOPERM;
+
+ case EFAULT:
+ return ISC_R_INVALIDARG;
+
+ case EEXIST:
+ return ISC_R_EXISTS;
+
+ case EINVAL:
+ return ISC_R_INVALIDARG;
+
+ case ENOTTY:
+ return ISC_R_INVALIDARG;
+
+ case EFBIG:
+ return ISC_R_NOSPACE;
+
+ case ENOSPC:
+ return ISC_R_NOSPACE;
+
+ case EROFS:
+ return ISC_R_NOPERM;
+
+ case EMLINK:
+ return ISC_R_NOSPACE;
+
+ case EPIPE:
+ return ISC_R_NOTCONNECTED;
+
+ case EINPROGRESS:
+ return ISC_R_ALREADYRUNNING;
+
+ case EALREADY:
+ return ISC_R_ALREADYRUNNING;
+
+ case ENOTSOCK:
+ return ISC_R_INVALIDFILE;
+
+ case EDESTADDRREQ:
+ return ISC_R_DESTADDRREQ;
+
+ case EMSGSIZE:
+ return ISC_R_NOSPACE;
+
+ case EPROTOTYPE:
+ return ISC_R_INVALIDARG;
+
+ case ENOPROTOOPT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EPROTONOSUPPORT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case ESOCKTNOSUPPORT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EOPNOTSUPP:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EPFNOSUPPORT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EAFNOSUPPORT:
+ return ISC_R_NOTIMPLEMENTED;
+
+ case EADDRINUSE:
+ return ISC_R_ADDRINUSE;
+
+ case EADDRNOTAVAIL:
+ return ISC_R_ADDRNOTAVAIL;
+
+ case ENETDOWN:
+ return ISC_R_NETDOWN;
+
+ case ENETUNREACH:
+ return ISC_R_NETUNREACH;
+
+ case ECONNABORTED:
+ return ISC_R_TIMEDOUT;
+
+ case ECONNRESET:
+ return ISC_R_CONNRESET;
+
+ case ENOBUFS:
+ return ISC_R_NOSPACE;
+
+ case EISCONN:
+ return ISC_R_ALREADYRUNNING;
+
+ case ENOTCONN:
+ return ISC_R_NOTCONNECTED;
+
+ case ESHUTDOWN:
+ return ISC_R_SHUTTINGDOWN;
+
+ case ETIMEDOUT:
+ return ISC_R_TIMEDOUT;
+
+ case ECONNREFUSED:
+ return ISC_R_CONNREFUSED;
+
+ case EHOSTDOWN:
+ return ISC_R_HOSTDOWN;
+
+ case EHOSTUNREACH:
+ return ISC_R_HOSTUNREACH;
+
+#ifdef EDQUOT
+ case EDQUOT:
+ return ISC_R_QUOTA;
+#endif
+
+#ifdef EBADRPC
+ case EBADRPC:
+ return ISC_R_NOTIMPLEMENTED;
+#endif
+
+#ifdef ERPCMISMATCH
+ case ERPCMISMATCH:
+ return ISC_R_VERSIONMISMATCH;
+#endif
+
+#ifdef EPROGMISMATCH
+ case EPROGMISMATCH:
+ return ISC_R_VERSIONMISMATCH;
+#endif
+
+#ifdef EAUTH
+ case EAUTH:
+ return ISC_R_NOTAUTH;
+#endif
+
+#ifdef ENEEDAUTH
+ case ENEEDAUTH:
+ return ISC_R_NOTAUTH;
+#endif
+
+#ifdef EOVERFLOW
+ case EOVERFLOW:
+ return ISC_R_NOSPACE;
+#endif
+ }
+ return ISC_R_UNEXPECTED;
+}
+
+ns_rcode isc_rcode_to_ns (isc_result_t isc)
+{
+ switch (isc) {
+ case ISC_R_SUCCESS:
+ return ns_r_noerror;
+
+ case ISC_R_FORMERR:
+ return ns_r_formerr;
+
+ case ISC_R_SERVFAIL:
+ return ns_r_servfail;
+
+ case ISC_R_NXDOMAIN:
+ return ns_r_nxdomain;
+
+ case ISC_R_NOTIMPL:
+ return ns_r_notimpl;
+
+ case ISC_R_REFUSED:
+ return ns_r_refused;
+
+ case ISC_R_YXDOMAIN:
+ return ns_r_yxdomain;
+
+ case ISC_R_YXRRSET:
+ return ns_r_yxrrset;
+
+ case ISC_R_NXRRSET:
+ return ns_r_nxrrset;
+
+ case ISC_R_NOTAUTH:
+ return ns_r_notauth;
+
+ case ISC_R_NOTZONE:
+ return ns_r_notzone;
+
+ case ISC_R_BADSIG:
+ return ns_r_badsig;
+
+ case ISC_R_BADKEY:
+ return ns_r_badkey;
+
+ case ISC_R_BADTIME:
+ return ns_r_badtime;
+
+ default:
+ ;
+ }
+ return ns_r_servfail;
+}
diff --git a/contrib/isc-dhcp/omapip/trace.c b/contrib/isc-dhcp/omapip/trace.c
new file mode 100644
index 000000000000..4ff3051647fc
--- /dev/null
+++ b/contrib/isc-dhcp/omapip/trace.c
@@ -0,0 +1,718 @@
+/* trace.c
+
+ Subroutines that support tracing of OMAPI wire transactions and
+ provide a mechanism for programs using OMAPI to trace their own
+ transactions... */
+
+/*
+ * Copyright (c) 2001 Internet Software Consortium.
+ * 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 Internet Software Consortium 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 INTERNET SOFTWARE CONSORTIUM 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 INTERNET SOFTWARE CONSORTIUM 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.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon, as part of a project for Nominum, Inc. To learn more
+ * about the Internet Software Consortium, see http://www.isc.org/. To
+ * learn more about Nominum, Inc., see ``http://www.nominum.com''.
+ */
+
+#include <omapip/omapip_p.h>
+
+#if defined (TRACING)
+void (*trace_set_time_hook) (u_int32_t);
+static int tracing_stopped;
+static int traceoutfile;
+static int traceindex;
+static trace_type_t **trace_types;
+static int trace_type_count;
+static int trace_type_max;
+static trace_type_t *new_trace_types;
+static FILE *traceinfile;
+static tracefile_header_t tracefile_header;
+static int trace_playback_flag;
+trace_type_t trace_time_marker;
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+extern omapi_array_t *trace_listeners;
+extern omapi_array_t *omapi_connections;
+
+void trace_free_all ()
+{
+ trace_type_t *tp;
+ int i;
+ tp = new_trace_types;
+ while (tp) {
+ new_trace_types = tp -> next;
+ if (tp -> name) {
+ dfree (tp -> name, MDL);
+ tp -> name = (char *)0;
+ }
+ dfree (tp, MDL);
+ tp = new_trace_types;
+ }
+ for (i = 0; i < trace_type_count; i++) {
+ if (trace_types [i]) {
+ if (trace_types [i] -> name)
+ dfree (trace_types [i] -> name, MDL);
+ dfree (trace_types [i], MDL);
+ }
+ }
+ dfree (trace_types, MDL);
+ trace_types = (trace_type_t **)0;
+ trace_type_count = trace_type_max = 0;
+
+ omapi_array_free (&trace_listeners, MDL);
+ omapi_array_free (&omapi_connections, MDL);
+}
+#endif
+
+static isc_result_t trace_type_record (trace_type_t *,
+ unsigned, const char *, int);
+
+int trace_playback ()
+{
+ return trace_playback_flag;
+}
+
+int trace_record ()
+{
+ if (traceoutfile && !tracing_stopped)
+ return 1;
+ return 0;
+}
+
+isc_result_t trace_init (void (*set_time) (u_int32_t),
+ const char *file, int line)
+{
+ trace_type_t *root_type;
+ static int root_setup = 0;
+
+ if (root_setup)
+ return ISC_R_SUCCESS;
+
+ trace_set_time_hook = set_time;
+
+ root_type = trace_type_register ("trace-index-mapping",
+ (void *)0, trace_index_map_input,
+ trace_index_stop_tracing, file, line);
+ if (!root_type)
+ return ISC_R_UNEXPECTED;
+ if (new_trace_types == root_type)
+ new_trace_types = new_trace_types -> next;
+ root_type -> index = 0;
+ trace_type_stash (root_type);
+
+ root_setup = 1;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t trace_begin (const char *filename,
+ const char *file, int line)
+{
+ tracefile_header_t tfh;
+ int status;
+ trace_type_t *tptr, *next;
+ isc_result_t result;
+
+ if (traceoutfile) {
+ log_error ("%s(%d): trace_begin called twice",
+ file, line);
+ return ISC_R_INVALIDARG;
+ }
+
+ traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL, 0644);
+ if (traceoutfile < 0) {
+ log_error ("%s(%d): trace_begin: %s: %m",
+ file, line, filename);
+ return ISC_R_UNEXPECTED;
+ }
+#if defined (HAVE_SETFD)
+ if (fcntl (traceoutfile, F_SETFD, 1) < 0)
+ log_error ("Can't set close-on-exec on %s: %m", filename);
+#endif
+
+ tfh.magic = htonl (TRACEFILE_MAGIC);
+ tfh.version = htonl (TRACEFILE_VERSION);
+ tfh.hlen = htonl (sizeof (tracefile_header_t));
+ tfh.phlen = htonl (sizeof (tracepacket_t));
+
+ status = write (traceoutfile, &tfh, sizeof tfh);
+ if (status < 0) {
+ log_error ("%s(%d): trace_begin write failed: %m", file, line);
+ return ISC_R_UNEXPECTED;
+ } else if (status != sizeof tfh) {
+ log_error ("%s(%d): trace_begin: short write (%d:%ld)",
+ file, line, status, (long)(sizeof tfh));
+ trace_stop ();
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Stash all the types that have already been set up. */
+ if (new_trace_types) {
+ next = new_trace_types;
+ new_trace_types = (trace_type_t *)0;
+ for (tptr = next; tptr; tptr = next) {
+ next = tptr -> next;
+ if (tptr -> index != 0) {
+ result = (trace_type_record
+ (tptr,
+ strlen (tptr -> name), file, line));
+ if (result != ISC_R_SUCCESS)
+ return status;
+ }
+ }
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t trace_write_packet (trace_type_t *ttype, unsigned length,
+ const char *buf, const char *file, int line)
+{
+ trace_iov_t iov;
+
+ iov.buf = buf;
+ iov.len = length;
+ return trace_write_packet_iov (ttype, 1, &iov, file, line);
+}
+
+isc_result_t trace_write_packet_iov (trace_type_t *ttype,
+ int count, trace_iov_t *iov,
+ const char *file, int line)
+{
+ tracepacket_t tmp;
+ int status;
+ int i;
+ int length;
+
+ /* Really shouldn't get called here, but it may be hard to turn off
+ tracing midstream if the trace file write fails or something. */
+ if (tracing_stopped)
+ return 0;
+
+ if (!ttype) {
+ log_error ("%s(%d): trace_write_packet with null trace type",
+ file ? file : "<unknown file>", line);
+ return ISC_R_INVALIDARG;
+ }
+ if (!traceoutfile) {
+ log_error ("%s(%d): trace_write_packet with no tracefile.",
+ file ? file : "<unknown file>", line);
+ return ISC_R_INVALIDARG;
+ }
+
+ /* Compute the total length of the iov. */
+ length = 0;
+ for (i = 0; i < count; i++)
+ length += iov [i].len;
+
+ /* We have to swap out the data, because it may be read back on a
+ machine of different endianness. */
+ tmp.type_index = htonl (ttype -> index);
+ tmp.when = htonl (time ((time_t *)0)); /* XXX */
+ tmp.length = htonl (length);
+
+ status = write (traceoutfile, &tmp, sizeof tmp);
+ if (status < 0) {
+ log_error ("%s(%d): trace_write_packet write failed: %m",
+ file, line);
+ return ISC_R_UNEXPECTED;
+ } else if (status != sizeof tmp) {
+ log_error ("%s(%d): trace_write_packet: short write (%d:%ld)",
+ file, line, status, (long)(sizeof tmp));
+ trace_stop ();
+ }
+
+ for (i = 0; i < count; i++) {
+ status = write (traceoutfile, iov [i].buf, iov [i].len);
+ if (status < 0) {
+ log_error ("%s(%d): %s write failed: %m",
+ file, line, "trace_write_packet");
+ return ISC_R_UNEXPECTED;
+ } else if (status != iov [i].len) {
+ log_error ("%s(%d): %s: short write (%d:%d)",
+ file, line,
+ "trace_write_packet", status, length);
+ trace_stop ();
+ }
+ }
+
+ /* Write padding on the end of the packet to align the next
+ packet to an 8-byte boundary. This is in case we decide to
+ use mmap in some clever way later on. */
+ if (length % 8) {
+ static char zero [] = { 0, 0, 0, 0, 0, 0, 0 };
+ unsigned padl = 8 - (length % 8);
+
+ status = write (traceoutfile, zero, padl);
+ if (status < 0) {
+ log_error ("%s(%d): trace_write_packet write failed: %m",
+ file, line);
+ return ISC_R_UNEXPECTED;
+ } else if (status != padl) {
+ log_error ("%s(%d): trace_write_packet: short write (%d:%d)",
+ file, line, status, padl);
+ trace_stop ();
+ }
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+void trace_type_stash (trace_type_t *tptr)
+{
+ trace_type_t **vec;
+ int delta;
+ if (trace_type_max <= tptr -> index) {
+ delta = tptr -> index - trace_type_max + 10;
+ vec = dmalloc (((trace_type_max + delta) *
+ sizeof (trace_type_t *)), MDL);
+ if (!vec)
+ return;
+ memset (&vec [trace_type_max], 0,
+ (sizeof (trace_type_t *)) * delta);
+ trace_type_max += delta;
+ if (trace_types) {
+ memcpy (vec, trace_types,
+ trace_type_count * sizeof (trace_type_t *));
+ dfree (trace_types, MDL);
+ }
+ trace_types = vec;
+ }
+ trace_types [tptr -> index] = tptr;
+ if (tptr -> index >= trace_type_count)
+ trace_type_count = tptr -> index + 1;
+}
+
+trace_type_t *trace_type_register (const char *name,
+ void *baggage,
+ void (*have_packet) (trace_type_t *,
+ unsigned, char *),
+ void (*stop_tracing) (trace_type_t *),
+ const char *file, int line)
+{
+ trace_type_t *ttmp, *tptr;
+ unsigned slen = strlen (name);
+ isc_result_t status;
+
+ ttmp = dmalloc (sizeof *ttmp, file, line);
+ if (!ttmp)
+ return ttmp;
+ ttmp -> index = -1;
+ ttmp -> name = dmalloc (slen + 1, file, line);
+ if (!ttmp -> name) {
+ dfree (ttmp, file, line);
+ return (trace_type_t *)0;
+ }
+ strcpy (ttmp -> name, name);
+ ttmp -> have_packet = have_packet;
+ ttmp -> stop_tracing = stop_tracing;
+
+ if (traceoutfile) {
+ status = trace_type_record (ttmp, slen, file, line);
+ if (status != ISC_R_SUCCESS) {
+ dfree (ttmp -> name, file, line);
+ dfree (ttmp, file, line);
+ return (trace_type_t *)0;
+ }
+ } else {
+ ttmp -> next = new_trace_types;
+ new_trace_types = ttmp;
+ }
+
+ return ttmp;
+}
+
+static isc_result_t trace_type_record (trace_type_t *ttmp, unsigned slen,
+ const char *file, int line)
+{
+ trace_index_mapping_t *tim;
+ isc_result_t status;
+
+ tim = dmalloc (slen + TRACE_INDEX_MAPPING_SIZE, file, line);
+ if (!tim)
+ return ISC_R_NOMEMORY;
+ ttmp -> index = ++traceindex;
+ trace_type_stash (ttmp);
+ tim -> index = htonl (ttmp -> index);
+ memcpy (tim -> name, ttmp -> name, slen);
+ status = trace_write_packet (trace_types [0],
+ slen + TRACE_INDEX_MAPPING_SIZE,
+ (char *)tim, file, line);
+ dfree (tim, file, line);
+ return status;
+}
+
+/* Stop all registered trace types from trying to trace. */
+
+void trace_stop (void)
+{
+ int i;
+
+ for (i = 0; i < trace_type_count; i++)
+ if (trace_types [i] -> stop_tracing)
+ (*(trace_types [i] -> stop_tracing))
+ (trace_types [i]);
+ tracing_stopped = 1;
+}
+
+void trace_index_map_input (trace_type_t *ttype, unsigned length, char *buf)
+{
+ trace_index_mapping_t *tmap;
+ unsigned len;
+ trace_type_t *tptr, **prev;
+
+ if (length < TRACE_INDEX_MAPPING_SIZE) {
+ log_error ("short trace index mapping");
+ return;
+ }
+ tmap = (trace_index_mapping_t *)buf;
+
+ prev = &new_trace_types;
+ for (tptr = new_trace_types; tptr; tptr = tptr -> next) {
+ len = strlen (tptr -> name);
+ if (len == length - TRACE_INDEX_MAPPING_SIZE &&
+ !memcmp (tptr -> name, tmap -> name, len)) {
+ tptr -> index = ntohl (tmap -> index);
+ trace_type_stash (tptr);
+ *prev = tptr -> next;
+ return;
+ }
+ prev = &tptr -> next;
+ }
+
+ log_error ("No registered trace type for type name %.*s",
+ (int)length - TRACE_INDEX_MAPPING_SIZE, tmap -> name);
+ return;
+}
+
+void trace_index_stop_tracing (trace_type_t *ttype) { }
+
+void trace_replay_init (void)
+{
+ trace_playback_flag = 1;
+}
+
+void trace_file_replay (const char *filename)
+{
+ tracepacket_t *tpkt = (tracepacket_t *)0;
+ int status;
+ char *buf = (char *)0;
+ unsigned buflen;
+ unsigned bufmax = 0;
+ trace_type_t *ttype = (trace_type_t *)0;
+ isc_result_t result;
+ int len;
+
+ traceinfile = fopen (filename, "r");
+ if (!traceinfile) {
+ log_error ("Can't open tracefile %s: %m", filename);
+ return;
+ }
+#if defined (HAVE_SETFD)
+ if (fcntl (fileno (traceinfile), F_SETFD, 1) < 0)
+ log_error ("Can't set close-on-exec on %s: %m", filename);
+#endif
+ status = fread (&tracefile_header, 1,
+ sizeof tracefile_header, traceinfile);
+ if (status < sizeof tracefile_header) {
+ if (ferror (traceinfile))
+ log_error ("Error reading trace file header: %m");
+ else
+ log_error ("Short read on trace file header: %d %ld.",
+ status, (long)(sizeof tracefile_header));
+ goto out;
+ }
+ tracefile_header.magic = ntohl (tracefile_header.magic);
+ tracefile_header.version = ntohl (tracefile_header.version);
+ tracefile_header.hlen = ntohl (tracefile_header.hlen);
+ tracefile_header.phlen = ntohl (tracefile_header.phlen);
+
+ if (tracefile_header.magic != TRACEFILE_MAGIC) {
+ log_error ("%s: not a dhcp trace file.", filename);
+ goto out;
+ }
+ if (tracefile_header.version > TRACEFILE_VERSION) {
+ log_error ("tracefile version %ld > current %ld.",
+ (long int)tracefile_header.version,
+ (long int)TRACEFILE_VERSION);
+ goto out;
+ }
+ if (tracefile_header.phlen < sizeof *tpkt) {
+ log_error ("tracefile packet size too small - %ld < %ld",
+ (long int)tracefile_header.phlen,
+ (long int)sizeof *tpkt);
+ goto out;
+ }
+ len = (sizeof tracefile_header) - tracefile_header.hlen;
+ if (len < 0) {
+ log_error ("tracefile header size too small - %ld < %ld",
+ (long int)tracefile_header.hlen,
+ (long int)sizeof tracefile_header);
+ goto out;
+ }
+ if (len > 0) {
+ status = fseek (traceinfile, (long)len, SEEK_CUR);
+ if (status < 0) {
+ log_error ("can't seek past header: %m");
+ goto out;
+ }
+ }
+
+ tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
+ if (!tpkt) {
+ log_error ("can't allocate trace packet header.");
+ goto out;
+ }
+
+ while ((result = trace_get_next_packet (&ttype, tpkt, &buf, &buflen,
+ &bufmax)) == ISC_R_SUCCESS) {
+ (*ttype -> have_packet) (ttype, tpkt -> length, buf);
+ ttype = (trace_type_t *)0;
+ }
+ out:
+ fclose (traceinfile);
+ if (buf)
+ dfree (buf, MDL);
+ if (tpkt)
+ dfree (tpkt, MDL);
+}
+
+/* Get the next packet from the file. If ttp points to a nonzero pointer
+ to a trace type structure, check the next packet to see if it's of the
+ expected type, and back off if not. */
+
+isc_result_t trace_get_next_packet (trace_type_t **ttp,
+ tracepacket_t *tpkt,
+ char **buf, unsigned *buflen,
+ unsigned *bufmax)
+{
+ trace_type_t *ttype;
+ unsigned paylen;
+ int status;
+ int len;
+ fpos_t curpos;
+
+ status = fgetpos (traceinfile, &curpos);
+ if (status < 0)
+ log_error ("Can't save tracefile position: %m");
+
+ status = fread (tpkt, 1, (size_t)tracefile_header.phlen, traceinfile);
+ if (status < tracefile_header.phlen) {
+ if (ferror (traceinfile))
+ log_error ("Error reading trace packet header: %m");
+ else if (status == 0)
+ return ISC_R_EOF;
+ else
+ log_error ("Short read on trace packet header: "
+ "%ld %ld.",
+ (long int)status,
+ (long int)tracefile_header.phlen);
+ return ISC_R_PROTOCOLERROR;
+ }
+
+ /* Swap the packet. */
+ tpkt -> type_index = ntohl (tpkt -> type_index);
+ tpkt -> length = ntohl (tpkt -> length);
+ tpkt -> when = ntohl (tpkt -> when);
+
+ /* See if there's a handler for this packet type. */
+ if (tpkt -> type_index < trace_type_count &&
+ trace_types [tpkt -> type_index])
+ ttype = trace_types [tpkt -> type_index];
+ else {
+ log_error ("Trace packet with unknown index %ld",
+ (long int)tpkt -> type_index);
+ return ISC_R_PROTOCOLERROR;
+ }
+
+ /* If we were just hunting for the time marker, we've found it,
+ so back up to the beginning of the packet and return its
+ type. */
+ if (ttp && *ttp == &trace_time_marker) {
+ *ttp = ttype;
+ status = fsetpos (traceinfile, &curpos);
+ if (status < 0) {
+ log_error ("fsetpos in tracefile failed: %m");
+ return ISC_R_PROTOCOLERROR;
+ }
+ return ISC_R_EXISTS;
+ }
+
+ /* If we were supposed to get a particular kind of packet,
+ check to see that we got the right kind. */
+ if (ttp && *ttp && ttype != *ttp) {
+ log_error ("Read packet type %s when expecting %s",
+ ttype -> name, (*ttp) -> name);
+ status = fsetpos (traceinfile, &curpos);
+ if (status < 0) {
+ log_error ("fsetpos in tracefile failed: %m");
+ return ISC_R_PROTOCOLERROR;
+ }
+ return ISC_R_UNEXPECTEDTOKEN;
+ }
+
+ paylen = tpkt -> length;
+ if (paylen % 8)
+ paylen += 8 - (tpkt -> length % 8);
+ if (paylen > (*bufmax)) {
+ if ((*buf))
+ dfree ((*buf), MDL);
+ (*bufmax) = ((paylen + 1023) & ~1023U);
+ (*buf) = dmalloc ((*bufmax), MDL);
+ if (!(*buf)) {
+ log_error ("Can't allocate input buffer sized %d",
+ (*bufmax));
+ return ISC_R_NOMEMORY;
+ }
+ }
+
+ status = fread ((*buf), 1, paylen, traceinfile);
+ if (status < paylen) {
+ if (ferror (traceinfile))
+ log_error ("Error reading trace payload: %m");
+ else
+ log_error ("Short read on trace payload: %d %d.",
+ status, paylen);
+ return ISC_R_PROTOCOLERROR;
+ }
+
+ /* Store the actual length of the payload. */
+ *buflen = tpkt -> length;
+
+ if (trace_set_time_hook)
+ (*trace_set_time_hook) (tpkt -> when);
+
+ if (ttp)
+ *ttp = ttype;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t trace_get_packet (trace_type_t **ttp,
+ unsigned *buflen, char **buf)
+{
+ tracepacket_t *tpkt;
+ unsigned bufmax = 0;
+ isc_result_t status;
+
+ if (!buf || *buf)
+ return ISC_R_INVALIDARG;
+
+ tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
+ if (!tpkt) {
+ log_error ("can't allocate trace packet header.");
+ return ISC_R_NOMEMORY;
+ }
+
+ status = trace_get_next_packet (ttp, tpkt, buf, buflen, &bufmax);
+
+ dfree (tpkt, MDL);
+ return status;
+}
+
+time_t trace_snoop_time (trace_type_t **ptp)
+{
+ tracepacket_t *tpkt;
+ unsigned bufmax = 0;
+ unsigned buflen = 0;
+ char *buf = (char *)0;
+ isc_result_t status;
+ time_t result;
+ trace_type_t *ttp;
+
+ if (!ptp)
+ ptp = &ttp;
+
+ tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
+ if (!tpkt) {
+ log_error ("can't allocate trace packet header.");
+ return ISC_R_NOMEMORY;
+ }
+
+ *ptp = &trace_time_marker;
+ trace_get_next_packet (ptp, tpkt, &buf, &buflen, &bufmax);
+ result = tpkt -> when;
+
+ dfree (tpkt, MDL);
+ return result;
+}
+
+/* Get a packet from the trace input file that contains a file with the
+ specified name. We don't hunt for the packet - it should be the next
+ packet in the tracefile. If it's not, or something else bad happens,
+ return an error code. */
+
+isc_result_t trace_get_file (trace_type_t *ttype,
+ const char *filename, unsigned *len, char **buf)
+{
+ fpos_t curpos;
+ unsigned max = 0;
+ tracepacket_t *tpkt;
+ int status;
+ isc_result_t result;
+
+ /* Disallow some obvious bogosities. */
+ if (!buf || !len || *buf)
+ return ISC_R_INVALIDARG;
+
+ /* Save file position in case of filename mismatch. */
+ status = fgetpos (traceinfile, &curpos);
+ if (status < 0)
+ log_error ("Can't save tracefile position: %m");
+
+ tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
+ if (!tpkt) {
+ log_error ("can't allocate trace packet header.");
+ return ISC_R_NOMEMORY;
+ }
+
+ result = trace_get_next_packet (&ttype, tpkt, buf, len, &max);
+ if (result != ISC_R_SUCCESS) {
+ dfree (tpkt, MDL);
+ if (*buf)
+ dfree (*buf, MDL);
+ return result;
+ }
+
+ /* Make sure the filename is right. */
+ if (strcmp (filename, *buf)) {
+ log_error ("Read file %s when expecting %s", *buf, filename);
+ status = fsetpos (traceinfile, &curpos);
+ if (status < 0) {
+ log_error ("fsetpos in tracefile failed: %m");
+ dfree (tpkt, MDL);
+ dfree (*buf, MDL);
+ return ISC_R_PROTOCOLERROR;
+ }
+ return ISC_R_UNEXPECTEDTOKEN;
+ }
+
+ dfree (tpkt, MDL);
+ return ISC_R_SUCCESS;
+}
+#endif /* TRACING */