summaryrefslogtreecommitdiff
path: root/omapip
diff options
context:
space:
mode:
authorTed Lemon <source@isc.org>1999-09-02 00:32:56 +0000
committerTed Lemon <source@isc.org>1999-09-02 00:32:56 +0000
commit61b844bfd7641a62d681a1f70d3b6dbc485ce4b6 (patch)
tree01e4c19e3b1025eade692fb7f5d6748099f96b01 /omapip
parenta40cbc2b969af1eeb0bdd1912040c3a829a5b220 (diff)
downloadisc-dhcp-61b844bfd7641a62d681a1f70d3b6dbc485ce4b6.tar.gz
Omapi library, initial checkin
Diffstat (limited to 'omapip')
-rw-r--r--omapip/Makefile.dist79
-rw-r--r--omapip/alloc.c443
-rw-r--r--omapip/buffer.c396
-rw-r--r--omapip/connection.c360
-rw-r--r--omapip/dispatch.c379
-rw-r--r--omapip/generic.c249
-rw-r--r--omapip/handle.c265
-rw-r--r--omapip/listener.c246
-rw-r--r--omapip/message.c294
-rw-r--r--omapip/omapi.30
-rw-r--r--omapip/protocol.c639
-rw-r--r--omapip/result.c76
-rw-r--r--omapip/support.c380
-rw-r--r--omapip/test.c80
14 files changed, 3886 insertions, 0 deletions
diff --git a/omapip/Makefile.dist b/omapip/Makefile.dist
new file mode 100644
index 00000000..86af6019
--- /dev/null
+++ b/omapip/Makefile.dist
@@ -0,0 +1,79 @@
+# Makefile.dist
+#
+# Copyright (c) 1996-1999 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 \
+ listener.c dispatch.c generic.c support.c handle.c message.c
+OBJ = protocol.o buffer.o alloc.o result.o connection.o \
+ listener.o dispatch.o generic.o support.o handle.o message.o
+MAN = omapi.3
+
+DEBUG = -g
+INCLUDES = $(BINDINC) -I../includes
+CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS)
+
+all: libomapi.a test $(CATMANPAGES)
+
+test: test.o libomapi.a
+ $(CC) $(DEBUG) -o test test.o libomapi.a
+
+libomapi.a: $(OBJ)
+ rm -f libomapi.a
+ ar cruv libomapi.a $(OBJ)
+ $(RANLIB) libomapi.a
+
+install: all
+ for dir in $(LIBMANDIR); 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
+ 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:
+ makedepend $(INCLUDES) $(PREDEFINES) $(SRCS)
+
+clean:
+ -rm -f $(OBJ)
+
+realclean: clean
+ -rm -f libdhcp.a *~ $(CATMANPAGES) $(SEDMANPAGES)
+
+distclean: realclean
+ -rm -f Makefile
+
+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/omapip/alloc.c b/omapip/alloc.c
new file mode 100644
index 00000000..59a65231
--- /dev/null
+++ b/omapip/alloc.c
@@ -0,0 +1,443 @@
+/* alloc.c
+
+ Functions supporting memory allocation for the object management
+ protocol... */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.h>
+
+isc_result_t omapi_object_reference (omapi_object_t **r,
+ omapi_object_t *h,
+ char *name)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: reference store into non-null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_object_dereference (omapi_object_t **h,
+ char *name)
+{
+ int outer_reference = 0;
+ int inner_reference = 0;
+ int handle_reference = 0;
+ int extra_references;
+ omapi_object_t *p;
+
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: dereference of null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("dereference of pointer with refcnt of zero!");
+#else
+ 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 - 1;
+ if (p -> inner)
+ --extra_references;
+ if (p -> handle)
+ --extra_references;
+ }
+ for (p = (*h) -> outer;
+ p && !extra_references; p = p -> outer) {
+ extra_references += p -> refcnt - 1;
+ if (p -> outer)
+ --extra_references;
+ if (p -> handle)
+ --extra_references;
+ }
+ } else
+ extra_references = 0;
+
+ if (!extra_references) {
+ if (inner_reference)
+ omapi_object_dereference
+ (&(*h) -> inner -> outer, name);
+ if (outer_reference)
+ omapi_object_dereference
+ (&(*h) -> outer -> inner, name);
+ if ((*h) -> type -> destroy)
+ (*((*h) -> type -> destroy)) (*h, name);
+ free (*h);
+ }
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_buffer_new (omapi_buffer_t **h,
+ char *name)
+{
+ omapi_buffer_t *t;
+ isc_result_t status;
+
+ t = (omapi_buffer_t *)malloc (sizeof *t);
+ if (!t)
+ return ISC_R_NOMEMORY;
+ memset (t, 0, sizeof *t);
+ status = omapi_buffer_reference (h, t, name);
+ if (status != ISC_R_SUCCESS)
+ free (t);
+ return status;
+}
+
+isc_result_t omapi_buffer_reference (omapi_buffer_t **r,
+ omapi_buffer_t *h,
+ char *name)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: reference store into non-null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_buffer_dereference (omapi_buffer_t **h,
+ char *name)
+{
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: dereference of null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("dereference of pointer with refcnt of zero!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ if (--(*h) -> refcnt == 0)
+ free (*h);
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_typed_data_new (omapi_typed_data_t **t,
+ omapi_datatype_t type, ...)
+{
+ va_list l;
+ omapi_typed_data_t *new;
+ int len;
+ int val;
+ char *s;
+
+ va_start (l, type);
+
+ switch (type) {
+ case omapi_datatype_int:
+ len = OMAPI_TYPED_DATA_INT_LEN;
+ val = va_arg (l, int);
+ break;
+ case omapi_datatype_string:
+ s = va_arg (l, char *);
+ val = strlen (s);
+ len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val + 1;
+ break;
+ case omapi_datatype_data:
+ val = va_arg (l, int);
+ len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val;
+ break;
+ case omapi_datatype_object:
+ len = OMAPI_TYPED_DATA_OBJECT_LEN;
+ break;
+ default:
+ return ISC_R_INVALIDARG;
+ }
+
+ new = malloc (len);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, len);
+
+ switch (type) {
+ case omapi_datatype_int:
+ new -> u.integer = val;
+ break;
+ case omapi_datatype_string:
+ strcpy (new -> u.buffer.value, s);
+ new -> u.buffer.len = val;
+ break;
+ case omapi_datatype_data:
+ new -> u.buffer.len = val;
+ break;
+ case omapi_datatype_object:
+ return omapi_object_reference (&new -> u.object,
+ va_arg (l, omapi_object_t *),
+ "omapi_datatype_new");
+ break;
+ }
+ return omapi_typed_data_reference (t, new, "omapi_typed_data_new");
+}
+
+isc_result_t omapi_typed_data_reference (omapi_typed_data_t **r,
+ omapi_typed_data_t *h,
+ char *name)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: reference store into non-null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_typed_data_dereference (omapi_typed_data_t **h,
+ char *name)
+{
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: dereference of null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("dereference of pointer with refcnt of zero!");
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ 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,
+ name);
+ break;
+ }
+ free (*h);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_data_string_new (omapi_data_string_t **d,
+ int len, char *name)
+{
+ omapi_data_string_t *new;
+
+ new = malloc (OMAPI_DATA_STRING_EMPTY_SIZE + len);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, OMAPI_DATA_STRING_EMPTY_SIZE);
+ new -> len = len;
+ return omapi_data_string_reference (d, new, name);
+}
+
+isc_result_t omapi_data_string_reference (omapi_data_string_t **r,
+ omapi_data_string_t *h,
+ char *name)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: reference store into non-null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_data_string_dereference (omapi_data_string_t **h,
+ char *name)
+{
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: dereference of null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("dereference of pointer with refcnt of zero!");
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if (--((*h) -> refcnt) <= 0 ) {
+ free (*h);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_value_new (omapi_value_t **d,
+ char *name)
+{
+ omapi_value_t *new;
+
+ new = malloc (sizeof *new);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (new, 0, sizeof *new);
+ return omapi_value_reference (d, new, name);
+}
+
+isc_result_t omapi_value_reference (omapi_value_t **r,
+ omapi_value_t *h,
+ char *name)
+{
+ if (!h || !r)
+ return ISC_R_INVALIDARG;
+
+ if (*r) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: reference store into non-null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+ *r = h;
+ h -> refcnt++;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_value_dereference (omapi_value_t **h,
+ char *name)
+{
+ if (!h)
+ return ISC_R_INVALIDARG;
+
+ if (!*h) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("%s: dereference of null pointer!", name);
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if ((*h) -> refcnt <= 0) {
+#if defined (ALLOCATION_DEBUGGING)
+ abort ("dereference of pointer with refcnt of zero!");
+#else
+ return ISC_R_INVALIDARG;
+#endif
+ }
+
+ if (--((*h) -> refcnt) <= 0 ) {
+ if ((*h) -> name)
+ omapi_data_string_dereference (&(*h) -> name, name);
+ if ((*h) -> value)
+ omapi_typed_data_dereference (&(*h) -> value, name);
+ free (*h);
+ }
+ *h = 0;
+ return ISC_R_SUCCESS;
+}
+
diff --git a/omapip/buffer.c b/omapip/buffer.c
new file mode 100644
index 00000000..6bd2c946
--- /dev/null
+++ b/omapip/buffer.c
@@ -0,0 +1,396 @@
+/* buffer.c
+
+ Buffer access functions for the object management protocol... */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.h>
+
+/* 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)
+{
+ omapi_buffer_t *buffer;
+ isc_result_t status;
+ int read_len, read_status;
+ omapi_connection_object_t *c;
+ int 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_AVAIL (buffer)) {
+ status = omapi_buffer_new (&buffer -> next,
+ "omapi_private_read");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ buffer = buffer -> next;
+ }
+ } else {
+ status = omapi_buffer_new (&c -> inbufs,
+ "omapi_private_read");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ buffer = c -> inbufs;
+ }
+
+ bytes_to_read = BUFFER_BYTES_AVAIL (buffer);
+
+ while (bytes_to_read) {
+ if (buffer -> tail >= buffer -> head)
+ read_len = sizeof (buffer -> buf) - buffer -> tail - 1;
+ else
+ read_len = buffer -> tail - buffer -> head - 1;
+
+ read_status = read (c -> socket,
+ &buffer -> buf [buffer -> tail], read_len);
+ if (read_status < 0) {
+ if (errno == EWOULDBLOCK)
+ return ISC_R_NOMORE;
+ else if (errno == EIO)
+ return ISC_R_IOERROR;
+ else if (errno == EINVAL)
+ return ISC_R_INVALIDARG;
+ else if (errno == ECONNRESET) {
+ omapi_disconnect (h, 0);
+ return ISC_R_SHUTTINGDOWN;
+ } else
+ return ISC_R_UNEXPECTED;
+ }
+ if (read_status == 0) {
+ omapi_disconnect (h, 0);
+ return ISC_R_SHUTTINGDOWN;
+ }
+ 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,
+ unsigned char *bufp,
+ int len)
+{
+ omapi_buffer_t *buffer;
+ isc_result_t status;
+ int bytes_copied = 0;
+ int copy_len;
+ 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 (c -> outbufs) {
+ for (buffer = c -> outbufs;
+ buffer -> next; buffer = buffer -> next)
+ ;
+ } else {
+ status = omapi_buffer_new (&c -> outbufs,
+ "omapi_private_buffer_copyin");
+ 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_AVAIL (buffer)) {
+ status = (omapi_buffer_new
+ (&buffer -> next,
+ "omapi_private_buffer_copyin"));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ buffer = buffer -> next;
+ }
+
+ if (buffer -> tail < buffer -> head)
+ copy_len = buffer -> tail - buffer -> head - 1;
+ else
+ copy_len = sizeof (buffer -> buf) - buffer -> tail - 1;
+ if (copy_len > (len - bytes_copied))
+ copy_len = len - bytes_copied;
+
+ 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. */
+
+u_int32_t omapi_connection_copyout (unsigned char *buf,
+ omapi_object_t *h,
+ int size)
+{
+ int bytes_remaining;
+ int bytes_this_copy;
+ omapi_buffer_t *buffer;
+ unsigned char *bufp;
+ omapi_connection_object_t *c;
+
+ 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 (buffer -> head != buffer -> tail) {
+ if (buffer -> head > buffer -> tail) {
+ bytes_this_copy = (sizeof buffer -> buf -
+ buffer -> head);
+ } else {
+ bytes_this_copy =
+ buffer -> tail - buffer -> head;
+ }
+ if (bytes_this_copy > bytes_remaining)
+ bytes_this_copy = bytes_remaining;
+ if (bufp) {
+ memcpy (bufp, &buffer -> buf [buffer -> head],
+ bytes_this_copy);
+ bufp += bytes_this_copy;
+ }
+ bytes_remaining -= bytes_this_copy;
+ buffer -> head += bytes_this_copy;
+ if (buffer -> head == sizeof buffer -> buf)
+ buffer -> head = 0;
+ c -> in_bytes -= bytes_this_copy;
+ }
+
+ if (buffer -> head == buffer -> tail)
+ buffer = buffer -> next;
+ }
+
+ /* Get rid of any input buffers that we emptied. */
+ buffer = (omapi_buffer_t *)0;
+ while (c -> inbufs &&
+ c -> inbufs -> head == c -> inbufs -> tail) {
+ if (c -> inbufs -> next) {
+ omapi_buffer_reference
+ (&buffer,
+ c -> inbufs -> next,
+ "omapi_private_buffer_copyout");
+ omapi_buffer_dereference
+ (&c -> inbufs -> next,
+ "omapi_private_buffer_copyout");
+ }
+ omapi_buffer_dereference (&c -> inbufs,
+ "omapi_private_buffer_copyout");
+ omapi_buffer_reference (&c -> inbufs,
+ buffer,
+ "omapi_private_buffer_copyout");
+ omapi_buffer_dereference (&buffer,
+ "omapi_private_buffer_copyout");
+ }
+ return ISC_R_SUCCESS;
+}
+
+u_int32_t omapi_connection_writer (omapi_object_t *h)
+{
+ int bytes_this_write;
+ int bytes_written;
+ omapi_buffer_t *buffer;
+ unsigned char *bufp;
+ omapi_connection_object_t *c;
+
+ 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 (buffer -> head != buffer -> tail) {
+ if (buffer -> head > buffer -> tail) {
+ bytes_this_write = (sizeof buffer -> buf -
+ buffer -> head);
+ } else {
+ bytes_this_write =
+ (buffer -> tail - buffer -> head);
+ }
+ bytes_written = write (c -> socket,
+ &buffer -> buf [buffer -> head],
+ 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;
+ else if (errno == EFBIG || errno == EDQUOT)
+ 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;
+
+ buffer -> head += bytes_written;
+ if (buffer -> head == sizeof buffer -> buf)
+ buffer -> head = 0;
+ 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 (buffer -> head == buffer -> tail)
+ buffer = buffer -> next;
+ }
+
+ /* Get rid of any output buffers we emptied. */
+ buffer = (omapi_buffer_t *)0;
+ while (c -> outbufs &&
+ c -> outbufs -> head == c -> outbufs -> tail) {
+ if (c -> outbufs -> next) {
+ omapi_buffer_reference
+ (&buffer, c -> outbufs -> next,
+ "omapi_private_flush");
+ omapi_buffer_dereference
+ (&c -> outbufs -> next, "omapi_private_flush");
+ }
+ omapi_buffer_dereference (&c -> outbufs,
+ "omapi_private_flush");
+ if (buffer) {
+ omapi_buffer_reference (&c -> outbufs, buffer,
+ "omapi_private_flush");
+ omapi_buffer_dereference (&buffer,
+ "omapi_private_flush");
+ }
+ }
+ 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_int16_t value)
+{
+ u_int16_t inbuf;
+ isc_result_t status;
+
+ inbuf = htons (value);
+
+ return omapi_connection_copyin (c, (unsigned char *)&inbuf,
+ sizeof inbuf);
+}
+
diff --git a/omapip/connection.c b/omapip/connection.c
new file mode 100644
index 00000000..48cdd7c6
--- /dev/null
+++ b/omapip/connection.c
@@ -0,0 +1,360 @@
+/* connection.c
+
+ Subroutines for dealing with connections. */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.h>
+
+isc_result_t omapi_connect (omapi_object_t *c,
+ char *server_name,
+ int port)
+{
+ struct hostent *he;
+ int hix;
+ isc_result_t status;
+ omapi_connection_object_t *obj;
+
+ obj = (omapi_connection_object_t *)malloc (sizeof *obj);
+ if (!obj)
+ return ISC_R_NOMEMORY;
+ memset (obj, 0, sizeof *obj);
+ obj -> refcnt = 1;
+ obj -> type = omapi_type_connection;
+
+ status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
+ "omapi_protocol_connect");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_connect");
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, c,
+ "omapi_protocol_connect");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_connect");
+ return status;
+ }
+
+ /* Set up all the constants in the address... */
+ obj -> remote_addr.sin_port = htons (port);
+
+ /* First try for a numeric address, since that's easier to check. */
+ if (!inet_aton (server_name, &obj -> remote_addr.sin_addr)) {
+ /* 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) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_connect");
+ return ISC_R_HOSTUNKNOWN;
+ }
+ hix = 1;
+ memcpy (&obj -> remote_addr.sin_addr,
+ he -> h_addr_list [0],
+ sizeof obj -> remote_addr.sin_addr);
+ } else
+ he = (struct hostent *)0;
+
+ obj -> remote_addr.sin_len =
+ sizeof (struct sockaddr_in);
+ obj -> remote_addr.sin_family = AF_INET;
+ memset (&(obj -> remote_addr.sin_zero), 0,
+ sizeof obj -> remote_addr.sin_zero);
+
+ /* Create a socket on which to communicate. */
+ obj -> socket =
+ socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (obj -> socket < 0) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_connect");
+ if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
+ return ISC_R_NORESOURCES;
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Try to connect to the one IP address we were given, or any of
+ the IP addresses listed in the host's A RR. */
+ while (connect (obj -> socket,
+ ((struct sockaddr *)
+ &obj -> remote_addr),
+ sizeof obj -> remote_addr)) {
+ if (!he || !he -> h_addr_list [hix]) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_connect");
+ if (errno == ECONNREFUSED)
+ return ISC_R_CONNREFUSED;
+ if (errno == ENETUNREACH)
+ return ISC_R_NETUNREACH;
+ return ISC_R_UNEXPECTED;
+ }
+ memcpy (&obj -> remote_addr.sin_addr,
+ he -> h_addr_list [hix++],
+ sizeof obj -> remote_addr.sin_addr);
+ }
+
+ obj -> state = omapi_connection_connected;
+
+ /* I don't know why this would fail, so I'm tempted not to test
+ the return value. */
+ hix = sizeof (obj -> local_addr);
+ if (getsockname (obj -> socket,
+ ((struct sockaddr *)
+ &obj -> local_addr), &hix) < 0) {
+ }
+
+ if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_connect");
+ return ISC_R_UNEXPECTED;
+ }
+
+ status = omapi_register_io_object ((omapi_object_t *)obj,
+ omapi_connection_readfd,
+ omapi_connection_writefd,
+ omapi_connection_reader,
+ omapi_connection_writer,
+ omapi_connection_reaper);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_connect");
+ return status;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+/* 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;
+
+ c = (omapi_connection_object_t *)h;
+ if (c -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+
+ 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);
+ c -> state = omapi_connection_closed;
+
+ /* Disconnect from I/O object, if any. */
+ if (h -> outer)
+ omapi_object_dereference (&h -> outer, "omapi_disconnect");
+
+ /* 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, int 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;
+ if (c -> out_bytes)
+ return c -> socket;
+ else
+ return -1;
+}
+
+/* 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)
+ omapi_disconnect (h, 1);
+ if (c -> state == omapi_connection_closed)
+ return ISC_R_NOTCONNECTED;
+ 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)
+{
+ if (h -> type != omapi_type_connection)
+ 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_connection_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ if (h -> type != omapi_type_connection)
+ 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_connection_destroy (omapi_object_t *h, char *name)
+{
+ omapi_connection_object_t *c;
+
+ 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_object_dereference (&c -> listener, name);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
+ char *name, va_list ap)
+{
+ if (h -> type != omapi_type_connection)
+ 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_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;
+}
+
+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;
+
+ 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, 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;
+ return omapi_connection_copyin (c, data -> u.buffer.value,
+ data -> u.buffer.len);
+
+ case omapi_datatype_object:
+ status = omapi_object_handle (&handle,
+ data -> u.object);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ 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;
+}
+
diff --git a/omapip/dispatch.c b/omapip/dispatch.c
new file mode 100644
index 00000000..b7a666fd
--- /dev/null
+++ b/omapip/dispatch.c
@@ -0,0 +1,379 @@
+/* dispatch.c
+
+ I/O dispatcher. */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.h>
+
+static omapi_io_object_t omapi_io_states;
+u_int32_t cur_time;
+
+/* 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 = malloc (sizeof *obj);
+ if (!obj)
+ return ISC_R_NOMEMORY;
+ memset (obj, 0, sizeof *obj);
+
+ obj -> refcnt = 1;
+ obj -> type = omapi_type_io_object;
+
+ status = omapi_object_reference (&obj -> inner, h,
+ "omapi_register_io_object");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_register_io_object");
+ return status;
+ }
+
+ status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj,
+ "omapi_register_io_object");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_register_io_object");
+ 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)
+ p -> next = obj;
+ else
+ omapi_io_states.next = obj;
+
+ obj -> readfd = readfd;
+ obj -> writefd = writefd;
+ obj -> reader = reader;
+ obj -> writer = writer;
+ obj -> reaper = reaper;
+ 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 = malloc (sizeof *waiter);
+ if (!waiter)
+ return ISC_R_NOMEMORY;
+ memset (waiter, 0, sizeof *waiter);
+ waiter -> refcnt = 1;
+ waiter -> type = omapi_type_waiter;
+
+ /* 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,
+ "omapi_wait_for_completion");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&waiter,
+ "omapi_wait_for_completion");
+ return status;
+ }
+
+ status = omapi_object_reference (&inner -> inner,
+ (omapi_object_t *)waiter,
+ "omapi_wait_for_completion");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&waiter,
+ "omapi_wait_for_completion");
+ return status;
+ }
+ } else
+ waiter = (omapi_waiter_object_t *)0;
+
+ do {
+ status = omapi_one_dispatch (waiter, t);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ } while (!waiter || !waiter -> ready);
+
+ omapi_object_dereference ((omapi_object_t **)&waiter,
+ "omapi_wait_for_completion");
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_one_dispatch (omapi_waiter_object_t *waiter,
+ 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;
+
+ 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--;
+ }
+ }
+
+ /* If the object we're waiting on has reached completion,
+ return now. */
+ if (waiter && waiter -> ready)
+ return ISC_R_SUCCESS;
+
+ /* 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 &&
+ (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &r);
+ if (desc > max)
+ max = desc;
+ }
+
+ /* Same deal for write fdets. */
+ if (io -> writefd &&
+ (desc = (*(io -> writefd)) (io -> inner)) >= 0) {
+ FD_SET (desc, &w);
+ if (desc > max)
+ max = desc;
+ }
+ }
+
+ /* Wait for a packet or a timeout... XXX */
+ 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;
+
+ /* Not likely to be transitory... */
+ if (count < 0)
+ return ISC_R_UNEXPECTED;
+
+ for (io = omapi_io_states.next; io; io = io -> next) {
+ /* Check for a read descriptor, and if there is one,
+ see if we got input on that socket. */
+ if (io -> readfd &&
+ (desc = (*(io -> readfd)) (io -> inner)) >= 0) {
+ if (FD_ISSET (desc, &r))
+ status = ((*(io -> reader)) (io -> inner));
+ /* XXX what to do with status? */
+ }
+
+ /* Same deal for write descriptors. */
+ if (io -> writefd &&
+ (desc = (*(io -> writefd)) (io -> inner)) >= 0)
+ {
+ if (FD_ISSET (desc, &w))
+ status = ((*(io -> writer)) (io -> inner));
+ /* XXX what to do with status? */
+ }
+ }
+
+ /* 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) {
+ status = (*(io -> reaper)) (io -> inner);
+ if (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_object_reference
+ ((omapi_object_t **)&tmp,
+ (omapi_object_t *)io -> next,
+ "omapi_wfc");
+ if (prev) {
+ omapi_object_dereference
+ (((omapi_object_t **)
+ &prev -> next), "omapi_wfc");
+ if (tmp)
+ omapi_object_reference
+ (((omapi_object_t **)
+ &prev -> next),
+ (omapi_object_t *)tmp,
+ "omapi_wfc");
+ } else {
+ omapi_object_dereference
+ (((omapi_object_t **)
+ &omapi_io_states.next),
+ "omapi_wfc");
+ if (tmp)
+ omapi_object_reference
+ (((omapi_object_t **)
+ &omapi_io_states.next),
+ (omapi_object_t *)tmp,
+ "omapi_wfc");
+ else
+ omapi_signal_in
+ ((omapi_object_t *)
+ &omapi_io_states,
+ "ready");
+ }
+ if (tmp)
+ omapi_object_dereference
+ ((omapi_object_t **)&tmp,
+ "omapi_wfc");
+ }
+ }
+ 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, char *name)
+{
+ if (h -> type != omapi_type_io_object)
+ return ISC_R_INVALIDARG;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_io_signal_handler (omapi_object_t *h,
+ 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,
+ 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;
+ 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;
+}
+
diff --git a/omapip/generic.c b/omapip/generic.c
new file mode 100644
index 00000000..6c1ac3ce
--- /dev/null
+++ b/omapip/generic.c
@@ -0,0 +1,249 @@
+/* generic.c
+
+ Subroutines that support the generic object. */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.h>
+
+isc_result_t omapi_generic_new (omapi_object_t **gen, char *name)
+{
+ omapi_generic_object_t *obj;
+
+ obj = malloc (sizeof *obj);
+ if (!obj)
+ return ISC_R_NOMEMORY;
+ memset (obj, 0, sizeof *obj);
+ obj -> refcnt = 0;
+ obj -> type = omapi_type_generic;
+
+ return omapi_object_reference (gen, (omapi_object_t *)obj, name);
+}
+
+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;
+ int vm_new;
+ int i;
+ 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,
+ "omapi_message_get_value"));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ omapi_data_string_reference
+ (&new -> name, name,
+ "omapi_message_get_value");
+ if (value)
+ omapi_typed_data_reference
+ (&new -> value, value,
+ "omapi_generic_set_value");
+
+ omapi_value_dereference (&(g -> values [i]),
+ "omapi_message_set_value");
+ status = (omapi_value_reference
+ (&(g -> values [i]), new,
+ "omapi_message_set_value"));
+ omapi_value_dereference (&new,
+ "omapi_message_set_value");
+ return status;
+ }
+ }
+
+ /* 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 (g -> nvalues == g -> va_max) {
+ if (g -> va_max)
+ vm_new = 2 * g -> va_max;
+ else
+ vm_new = 10;
+ va = malloc (vm_new * sizeof *va);
+ if (!va)
+ return ISC_R_NOMEMORY;
+ if (g -> va_max)
+ memcpy (va, g -> values, g -> va_max * sizeof *va);
+ memset (va + g -> va_max, 0,
+ (vm_new - g -> va_max) * sizeof *va);
+ free (g -> values);
+ g -> values = va;
+ }
+ status = omapi_value_new (&g -> values [g -> nvalues],
+ "omapi_generic_set_value");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ omapi_data_string_reference (&g -> values [g -> nvalues] -> name, name,
+ "omapi_generic_set_value");
+ if (value)
+ omapi_typed_data_reference
+ (&g -> values [g -> nvalues] -> value, value,
+ "omapi_generic_set_value");
+ 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],
+ "omapi_message_get_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_generic_destroy (omapi_object_t *h, char *name)
+{
+ 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],
+ name);
+ }
+ free (g -> values);
+ g -> values = (omapi_value_t **)0;
+ g -> va_max = 0;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_generic_signal_handler (omapi_object_t *h,
+ 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) {
+ status = (omapi_connection_put_uint16
+ (c, src -> values [i] -> name -> len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_copyout
+ (src -> values [i] -> name -> value, c,
+ 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;
+}
+
diff --git a/omapip/handle.c b/omapip/handle.c
new file mode 100644
index 00000000..35d30ac3
--- /dev/null
+++ b/omapip/handle.c
@@ -0,0 +1,265 @@
+/* handle.c
+
+ Functions for maintaining handles on objects. */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.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 = malloc (sizeof *omapi_handle_table);
+ 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 = malloc (sizeof *new);
+ if (!new)
+ return ISC_R_NOMEMORY;
+ memset (omapi_handle_table, 0, sizeof *omapi_handle_table);
+ 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, "omapi_object_handle_in_table"));
+ 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 = malloc (sizeof *inner);
+ 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 = malloc (sizeof *new);
+ 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,
+ "omapi_handle_lookup_in");
+ }
+
+ /* 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);
+}
diff --git a/omapip/listener.c b/omapip/listener.c
new file mode 100644
index 00000000..57da4ace
--- /dev/null
+++ b/omapip/listener.c
@@ -0,0 +1,246 @@
+/* listener.c
+
+ Subroutines that support the generic listener object. */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.h>
+
+isc_result_t omapi_listen (omapi_object_t *h,
+ int port,
+ int max)
+{
+ struct hostent *he;
+ int hix;
+ isc_result_t status;
+ omapi_listener_object_t *obj;
+
+ /* Get the handle. */
+ obj = (omapi_listener_object_t *)malloc (sizeof *obj);
+ if (!obj)
+ return ISC_R_NOMEMORY;
+ obj -> refcnt = 1;
+ obj -> type = omapi_type_listener;
+
+ /* Connect this object to the inner object. */
+ status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj,
+ "omapi_protocol_listen");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_listen");
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, h,
+ "omapi_protocol_listen");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_listen");
+ return status;
+ }
+
+ /* Set up the address on which we will listen... */
+ obj -> address.sin_port = htons (port);
+ obj -> address.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ /* Create a socket on which to listen. */
+ obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (!obj -> socket) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_listen");
+ if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
+ return ISC_R_NORESOURCES;
+ return ISC_R_UNEXPECTED;
+ }
+
+ /* Try to bind to the wildcard address using the port number
+ we were given. */
+ if (bind (obj -> socket,
+ (struct sockaddr *)&obj -> address, sizeof obj -> address)) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_listen");
+ 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_object_dereference ((omapi_object_t **)&obj,
+ "omapi_listen");
+ return ISC_R_UNEXPECTED;
+ }
+
+ status = omapi_register_io_object ((omapi_object_t *)obj,
+ omapi_listener_readfd, 0,
+ omapi_accept, 0, 0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_listen");
+ return status;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+/* 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;
+ int len;
+ omapi_connection_object_t *obj;
+ omapi_listener_object_t *listener;
+
+ if (h -> type != omapi_type_listener)
+ return -1;
+ listener = (omapi_listener_object_t *)h;
+
+ /* Get the handle. */
+ obj = (omapi_connection_object_t *)malloc (sizeof *obj);
+ if (!obj)
+ return ISC_R_NOMEMORY;
+ obj -> refcnt = 1;
+ obj -> type = omapi_type_connection;
+
+ /* Accept the connection. */
+ len = sizeof obj -> remote_addr;
+ obj -> socket =
+ accept (listener -> socket,
+ ((struct sockaddr *)
+ &(obj -> remote_addr)), &len);
+ if (!obj -> socket) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_accept");
+ if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
+ return ISC_R_NORESOURCES;
+ return ISC_R_UNEXPECTED;
+ }
+
+ obj -> state = omapi_connection_connected;
+
+ status = omapi_register_io_object ((omapi_object_t *)obj,
+ omapi_connection_readfd,
+ omapi_connection_writefd,
+ omapi_connection_reader,
+ omapi_connection_writer,
+ omapi_connection_reaper);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_accept");
+ return status;
+ }
+
+ omapi_object_reference (&obj -> listener, (omapi_object_t *)listener,
+ "omapi_accept");
+
+ status = omapi_signal (h, "connect", obj);
+
+ /* Lose our reference to the connection, so it'll be gc'd when it's
+ reaped. */
+ omapi_object_dereference ((omapi_object_t **)&obj, "omapi_accept");
+ return status;
+}
+
+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, char *name)
+{
+ omapi_listener_object_t *l;
+
+ if (h -> type != omapi_type_listener)
+ return ISC_R_INVALIDARG;
+ l = (omapi_listener_object_t *)(h);
+
+ 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,
+ 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/omapip/message.c b/omapip/message.c
new file mode 100644
index 00000000..04f23142
--- /dev/null
+++ b/omapip/message.c
@@ -0,0 +1,294 @@
+/* message.c
+
+ Subroutines for dealing with message objects. */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.h>
+
+omapi_message_object_t *omapi_registered_messages;
+
+isc_result_t omapi_message_new (omapi_object_t **o, char *name)
+{
+ omapi_message_object_t *m;
+ isc_result_t status;
+
+ m = malloc (sizeof *m);
+ if (!m)
+ return ISC_R_NOMEMORY;
+ memset (m, 0, sizeof *m);
+ m -> type = omapi_type_message;
+ m -> refcnt = 1;
+
+ status = omapi_object_reference (o, (omapi_object_t *)m, name);
+ omapi_object_dereference ((omapi_object_t **)&m, name);
+ 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,
+ "omapi_message_set_value");
+ omapi_typed_data_reference (&m -> authenticator,
+ value,
+ "omapi_message_set_value");
+ 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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;
+ }
+
+ /* 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, m -> authlen,
+ "omapi_message_get_value");
+ else if (!omapi_ds_strcmp (name, "authenticator")) {
+ if (m -> authenticator)
+ return omapi_make_value (value,
+ name, m -> authenticator,
+ "omapi_message_get_value");
+ else
+ return ISC_R_NOTFOUND;
+ } else if (!omapi_ds_strcmp (name, "authid")) {
+ return omapi_make_int_value (value, name, m -> authid,
+ "omapi_message_get_value");
+ } else if (!omapi_ds_strcmp (name, "op")) {
+ return omapi_make_int_value (value, name, m -> op,
+ "omapi_message_get_value");
+ } else if (!omapi_ds_strcmp (name, "handle")) {
+ return omapi_make_int_value (value, name, m -> handle,
+ "omapi_message_get_value");
+ } else if (!omapi_ds_strcmp (name, "id")) {
+ return omapi_make_int_value (value, name, m -> id,
+ "omapi_message_get_value");
+ } else if (!omapi_ds_strcmp (name, "rid")) {
+ return omapi_make_int_value (value, name, m -> rid,
+ "omapi_message_get_value");
+ }
+
+ /* 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, char *name)
+{
+ int i;
+
+ omapi_message_object_t *m;
+ if (h -> type != omapi_type_message)
+ return ISC_R_INVALIDARG;
+ if (m -> authenticator) {
+ omapi_typed_data_dereference (&m -> authenticator, name);
+ }
+ if (!m -> prev && omapi_registered_messages != m)
+ omapi_message_unregister (h);
+ if (m -> prev)
+ omapi_object_dereference ((omapi_object_t **)&m -> prev, name);
+ if (m -> next)
+ omapi_object_dereference ((omapi_object_t **)&m -> next, name);
+ if (m -> id_object)
+ omapi_object_dereference ((omapi_object_t **)&m -> id_object,
+ name);
+ if (m -> object)
+ omapi_object_dereference ((omapi_object_t **)&m -> object,
+ name);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_message_signal_handler (omapi_object_t *h,
+ char *name, va_list ap)
+{
+ if (h -> type != omapi_type_message)
+ 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_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,
+ "omapi_message_register");
+ omapi_object_reference
+ ((omapi_object_t **)&omapi_registered_messages -> prev,
+ (omapi_object_t *)m, "omapi_message_register");
+ omapi_object_dereference
+ ((omapi_object_t **)&omapi_registered_messages,
+ "omapi_message_register");
+ }
+ omapi_object_reference
+ ((omapi_object_t **)&omapi_registered_messages,
+ (omapi_object_t *)m, "omapi_message_register");
+ 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,
+ "omapi_message_unregister");
+ omapi_object_dereference ((omapi_object_t **)&m -> next,
+ "omapi_message_unregister");
+ }
+ 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,
+ "omapi_message_register");
+ omapi_object_dereference ((omapi_object_t **)&m -> prev,
+ "omapi_message_unregister");
+ if (tmp -> next)
+ omapi_object_dereference
+ ((omapi_object_t **)&tmp -> next,
+ "omapi_message_unregister");
+ if (n)
+ omapi_object_reference
+ ((omapi_object_t **)&tmp -> next,
+ (omapi_object_t *)n,
+ "omapi_message_unregister");
+ omapi_object_dereference ((omapi_object_t **)&tmp,
+ "omapi_message_unregister");
+ } else {
+ omapi_object_dereference
+ ((omapi_object_t **)&omapi_registered_messages,
+ "omapi_unregister_message");
+ if (n)
+ omapi_object_reference
+ ((omapi_object_t **)&omapi_registered_messages,
+ (omapi_object_t *)n,
+ "omapi_message_unregister");
+ }
+ if (n)
+ omapi_object_dereference ((omapi_object_t **)&n,
+ "omapi_message_unregister");
+ return ISC_R_SUCCESS;
+}
diff --git a/omapip/omapi.3 b/omapip/omapi.3
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/omapip/omapi.3
diff --git a/omapip/protocol.c b/omapip/protocol.c
new file mode 100644
index 00000000..f8656389
--- /dev/null
+++ b/omapip/protocol.c
@@ -0,0 +1,639 @@
+/* protocol.c
+
+ Functions supporting the object management protocol... */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.h>
+
+isc_result_t omapi_protocol_connect (omapi_object_t *h,
+ char *server_name,
+ int port,
+ omapi_object_t *authinfo)
+{
+ isc_result_t status;
+ omapi_protocol_object_t *obj;
+
+ obj = (omapi_protocol_object_t *)malloc (sizeof *obj);
+ if (!obj)
+ return ISC_R_NOMEMORY;
+ memset (obj, 0, sizeof *obj);
+ obj -> refcnt = 1;
+ obj -> type = omapi_type_protocol;
+
+ status = omapi_connect ((omapi_object_t *)obj, server_name, port);
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_connect");
+ return status;
+ }
+ status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj,
+ "omapi_protocol_connect");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_connect");
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, h,
+ "omapi_protocol_connect");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_connect");
+ return status;
+ }
+
+ /* 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) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_connect");
+ return status;
+ }
+
+ if (authinfo)
+ omapi_object_reference (&obj -> authinfo, authinfo,
+ "omapi_protocol_connect");
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_accept");
+ return ISC_R_SUCCESS;
+}
+
+/* Send the protocol introduction message. */
+isc_result_t omapi_protocol_send_intro (omapi_object_t *h,
+ int ver,
+ int hsize)
+{
+ isc_result_t status;
+ omapi_protocol_object_t *p;
+
+ 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;
+ omapi_message_object_t *om;
+ isc_result_t status;
+ u_int32_t foo;
+
+ 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;
+
+ /* XXX Write the authenticator length */
+ status = omapi_connection_put_uint32 (c, 0);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ /* XXX Write the ID of the authentication key we're using. */
+ status = omapi_connection_put_uint32 (c, 0);
+ 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 -> handle));
+ 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 : 0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Now stuff out all the published name/value pairs associated
+ with the message. */
+ 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. */
+ status = omapi_connection_put_uint16 (c, 0);
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* XXX Write the authenticator... */
+
+ return ISC_R_SUCCESS;
+}
+
+
+isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
+ char *name, va_list ap)
+{
+ isc_result_t status;
+ omapi_protocol_object_t *p;
+ omapi_object_t *c;
+ u_int16_t nlen;
+ u_int32_t vlen;
+
+ if (h -> type != omapi_type_protocol) {
+ /* XXX shouldn't happen. Put an assert here? */
+ return ISC_R_UNEXPECTED;
+ }
+ p = (omapi_protocol_object_t *)h;
+
+ /* 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;
+ }
+
+ 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:
+ status = omapi_message_new ((omapi_object_t **)&p -> message,
+ "omapi_protocol_signal_handler");
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* We need a generic object to hang off of the
+ incoming message. */
+ status = omapi_generic_new (&p -> message -> object,
+ "omapi_protocol_signal_handler");
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ /* Swap in the header... */
+ omapi_connection_get_uint32 (c, &p -> message -> authid);
+
+ /* XXX bind the authenticator here! */
+ omapi_connection_get_uint32 (c, &p -> message -> authlen);
+ omapi_connection_get_uint32 (c, &p -> message -> op);
+ omapi_connection_get_uint32 (c, &p -> message -> handle);
+ 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. */
+
+ 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 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, "omapi_protocol_signal_handler"));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+ 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. */
+ 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
+ (&p -> value, omapi_datatype_data, nlen,
+ "omapi_protocol_signal_handler"));
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+
+ 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:
+ 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, "omapi_protocol_signal_handler");
+ omapi_typed_data_dereference (&p -> value,
+ "omapi_protocol_signal_handler");
+ goto need_name_length;
+
+ signature_wait:
+ case omapi_protocol_signature_wait:
+ status = omapi_typed_data_new (&p -> message -> authenticator,
+ omapi_datatype_data,
+ p -> message -> authlen);
+
+ if (status != ISC_R_SUCCESS) {
+ omapi_disconnect (c, 1);
+ return ISC_R_NOMEMORY;
+ }
+ omapi_connection_copyout
+ (p -> message -> authenticator -> u.buffer.value, c,
+ p -> message -> authlen);
+ /* XXX now do something to verify the signature. */
+
+ message_done:
+ /* XXX process the message. */
+ /* XXX unbind the authenticator. */
+
+ /* Now wait for the next message. */
+ goto to_header_wait;
+
+ default:
+ /* XXX should never get here. Assertion? */
+ }
+ return ISC_R_SUCCESS;
+}
+
+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)
+{
+ if (h -> type != omapi_type_protocol)
+ 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_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)
+ 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_destroy (omapi_object_t *h, char *name)
+{
+ 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_object_dereference ((omapi_object_t **)&p -> message,
+ name);
+ if (p -> authinfo)
+ return omapi_object_dereference (&p -> authinfo, name);
+ 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;
+}
+
+/* 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,
+ int port,
+ int max)
+{
+ isc_result_t status;
+ omapi_protocol_listener_object_t *obj;
+
+ obj = (omapi_protocol_listener_object_t *)malloc (sizeof *obj);
+ if (!obj)
+ return ISC_R_NOMEMORY;
+ memset (obj, 0, sizeof *obj);
+ obj -> refcnt = 1;
+ obj -> type = omapi_type_protocol_listener;
+
+ status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj,
+ "omapi_protocol_listen");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_listen");
+ return status;
+ }
+ status = omapi_object_reference (&obj -> inner, h,
+ "omapi_protocol_listen");
+ if (status != ISC_R_SUCCESS) {
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_listen");
+ return status;
+ }
+
+ status = omapi_listen ((omapi_object_t *)obj, port, max);
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_listen");
+ 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,
+ 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 *)malloc (sizeof *obj);
+ if (!obj)
+ return ISC_R_NOMEMORY;
+ memset (obj, 0, sizeof *obj);
+ obj -> refcnt = 1;
+ obj -> type = omapi_type_protocol;
+
+ status = omapi_object_reference (&obj -> outer, c,
+ "omapi_protocol_accept");
+ if (status != ISC_R_SUCCESS) {
+ lose:
+ omapi_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_accept");
+ omapi_disconnect (c, 1);
+ return status;
+ }
+
+ status = omapi_object_reference (&c -> inner, (omapi_object_t *)obj,
+ "omapi_protocol_accept");
+ 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_object_dereference ((omapi_object_t **)&obj,
+ "omapi_protocol_accept");
+ 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, char *name)
+{
+ 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;
+}
+
diff --git a/omapip/result.c b/omapip/result.c
new file mode 100644
index 00000000..8417b2cf
--- /dev/null
+++ b/omapip/result.c
@@ -0,0 +1,76 @@
+/* result.c
+
+ Cheap knock-off of libisc result table code. This is just a place-holder
+ until the actual libisc merge. */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.h>
+
+static 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 */
+};
+
+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/omapip/support.c b/omapip/support.c
new file mode 100644
index 00000000..1e8decf1
--- /dev/null
+++ b/omapip/support.c
@@ -0,0 +1,380 @@
+/* support.c
+
+ Subroutines providing general support for objects. */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#include <omapip/omapip.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_object_types;
+int omapi_object_type_count;
+static int ot_max;
+
+isc_result_t omapi_init (void)
+{
+ isc_result_t status;
+
+ /* 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_object_type_register (&omapi_type_waiter,
+ "waiter",
+ 0,
+ 0,
+ 0,
+ omapi_waiter_signal_handler, 0);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ /* This seems silly, but leave it. */
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_object_type_register (omapi_object_type_t **type,
+ 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 *, char *),
+ isc_result_t (*signal_handler)
+ (omapi_object_t *,
+ char *, va_list),
+ isc_result_t (*stuff_values)
+ (omapi_object_t *,
+ omapi_object_t *,
+ omapi_object_t *))
+{
+ omapi_object_type_t *t;
+
+ if (!omapi_object_types) {
+ ot_max = 10;
+ omapi_object_types = malloc (ot_max *
+ sizeof *omapi_object_types);
+ if (!omapi_object_types)
+ return ISC_R_NOMEMORY;
+ memset (omapi_object_types, 0, (ot_max *
+ sizeof *omapi_object_types));
+ } else if (omapi_object_type_count == ot_max) {
+ t = malloc (2 *ot_max * sizeof *t);
+ if (!t)
+ return ISC_R_NOMEMORY;
+ memcpy (t, omapi_object_types, ot_max *sizeof *t);
+ memset (t + ot_max, 0, ot_max * sizeof *t);
+ free (omapi_object_types);
+ omapi_object_types = t;
+ }
+ omapi_object_types [omapi_object_type_count].name = name;
+ omapi_object_types [omapi_object_type_count].set_value = set_value;
+ omapi_object_types [omapi_object_type_count].get_value = get_value;
+ omapi_object_types [omapi_object_type_count].destroy = destroy;
+ omapi_object_types [omapi_object_type_count].signal_handler =
+ signal_handler;
+ omapi_object_types [omapi_object_type_count].stuff_values =
+ stuff_values;
+ if (type)
+ *type = &omapi_object_types [omapi_object_type_count];
+ omapi_object_type_count++;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_signal (omapi_object_t *handle, 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, 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;
+
+ for (outer = h; outer -> outer; outer = outer -> outer)
+ ;
+ if (outer -> type -> set_value)
+ return (*(outer -> type -> set_value)) (outer,
+ id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+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_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;
+}
+
+int omapi_data_string_cmp (omapi_data_string_t *s1, omapi_data_string_t *s2)
+{
+ int 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, char *s2)
+{
+ int 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;
+}
+
+isc_result_t omapi_make_value (omapi_value_t **vp, omapi_data_string_t *name,
+ omapi_typed_data_t *value, char *caller)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, caller);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name, name, caller);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, caller);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_reference (&(*vp) -> value,
+ value, caller);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, caller);
+ return status;
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_make_const_value (omapi_value_t **vp,
+ omapi_data_string_t *name,
+ u_int8_t *value, int len, char *caller)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, caller);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name, name, caller);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, caller);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_new (&(*vp) -> value,
+ omapi_datatype_data, len);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, caller);
+ 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, char *caller)
+{
+ isc_result_t status;
+
+ status = omapi_value_new (vp, caller);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_data_string_reference (&(*vp) -> name, name, caller);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, caller);
+ return status;
+ }
+ if (value) {
+ status = omapi_typed_data_new (&(*vp) -> value,
+ omapi_datatype_int);
+ if (status != ISC_R_SUCCESS) {
+ omapi_value_dereference (vp, caller);
+ return status;
+ }
+ (*vp) -> value -> u.integer = value;
+ }
+ return ISC_R_SUCCESS;
+}
+
diff --git a/omapip/test.c b/omapip/test.c
new file mode 100644
index 00000000..4c0e164f
--- /dev/null
+++ b/omapip/test.c
@@ -0,0 +1,80 @@
+/* test.c
+
+ Test code for omapip... */
+
+/*
+ * Copyright (c) 1996-1999 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.
+ */
+
+#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, "main");
+ if (status != ISC_R_SUCCESS) {
+ fprintf (stderr, "omapi_generic_new: %s\n",
+ isc_result_totext (status));
+ exit (1);
+ }
+ status = omapi_protocol_listen (listener,
+ 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, "main");
+ 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], 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;
+}