]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Omapi library, initial checkin
authorTed Lemon <source@isc.org>
Thu, 2 Sep 1999 00:32:56 +0000 (00:32 +0000)
committerTed Lemon <source@isc.org>
Thu, 2 Sep 1999 00:32:56 +0000 (00:32 +0000)
14 files changed:
omapip/Makefile.dist [new file with mode: 0644]
omapip/alloc.c [new file with mode: 0644]
omapip/buffer.c [new file with mode: 0644]
omapip/connection.c [new file with mode: 0644]
omapip/dispatch.c [new file with mode: 0644]
omapip/generic.c [new file with mode: 0644]
omapip/handle.c [new file with mode: 0644]
omapip/listener.c [new file with mode: 0644]
omapip/message.c [new file with mode: 0644]
omapip/omapi.3 [new file with mode: 0644]
omapip/protocol.c [new file with mode: 0644]
omapip/result.c [new file with mode: 0644]
omapip/support.c [new file with mode: 0644]
omapip/test.c [new file with mode: 0644]

diff --git a/omapip/Makefile.dist b/omapip/Makefile.dist
new file mode 100644 (file)
index 0000000..86af601
--- /dev/null
@@ -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 (file)
index 0000000..59a6523
--- /dev/null
@@ -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 (file)
index 0000000..6bd2c94
--- /dev/null
@@ -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 (file)
index 0000000..48cdd7c
--- /dev/null
@@ -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 (file)
index 0000000..b7a666f
--- /dev/null
@@ -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 (file)
index 0000000..6c1ac3c
--- /dev/null
@@ -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 (file)
index 0000000..35d30ac
--- /dev/null
@@ -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 (file)
index 0000000..57da4ac
--- /dev/null
@@ -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 (file)
index 0000000..04f2314
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/omapip/protocol.c b/omapip/protocol.c
new file mode 100644 (file)
index 0000000..f865638
--- /dev/null
@@ -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 (file)
index 0000000..8417b2c
--- /dev/null
@@ -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 (file)
index 0000000..1e8decf
--- /dev/null
@@ -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 (file)
index 0000000..4c0e164
--- /dev/null
@@ -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;
+}