diff options
author | Ted Lemon <source@isc.org> | 1999-09-02 00:32:56 +0000 |
---|---|---|
committer | Ted Lemon <source@isc.org> | 1999-09-02 00:32:56 +0000 |
commit | 61b844bfd7641a62d681a1f70d3b6dbc485ce4b6 (patch) | |
tree | 01e4c19e3b1025eade692fb7f5d6748099f96b01 | |
parent | a40cbc2b969af1eeb0bdd1912040c3a829a5b220 (diff) | |
download | isc-dhcp-61b844bfd7641a62d681a1f70d3b6dbc485ce4b6.tar.gz |
Omapi library, initial checkin
-rw-r--r-- | omapip/Makefile.dist | 79 | ||||
-rw-r--r-- | omapip/alloc.c | 443 | ||||
-rw-r--r-- | omapip/buffer.c | 396 | ||||
-rw-r--r-- | omapip/connection.c | 360 | ||||
-rw-r--r-- | omapip/dispatch.c | 379 | ||||
-rw-r--r-- | omapip/generic.c | 249 | ||||
-rw-r--r-- | omapip/handle.c | 265 | ||||
-rw-r--r-- | omapip/listener.c | 246 | ||||
-rw-r--r-- | omapip/message.c | 294 | ||||
-rw-r--r-- | omapip/omapi.3 | 0 | ||||
-rw-r--r-- | omapip/protocol.c | 639 | ||||
-rw-r--r-- | omapip/result.c | 76 | ||||
-rw-r--r-- | omapip/support.c | 380 | ||||
-rw-r--r-- | omapip/test.c | 80 |
14 files changed, 3886 insertions, 0 deletions
diff --git a/omapip/Makefile.dist b/omapip/Makefile.dist new file mode 100644 index 00000000..86af6019 --- /dev/null +++ b/omapip/Makefile.dist @@ -0,0 +1,79 @@ +# Makefile.dist +# +# Copyright (c) 1996-1999 Internet Software Consortium. +# Use is subject to license terms which appear in the file named +# ISC-LICENSE that should have accompanied this file when you +# received it. If a file named ISC-LICENSE did not accompany this +# file, or you are not sure the one you have is correct, you may +# obtain an applicable copy of the license at: +# +# http://www.isc.org/isc-license-1.0.html. +# +# This file is part of the ISC DHCP distribution. The documentation +# associated with this file is listed in the file DOCUMENTATION, +# included in the top-level directory of this release. +# +# Support and other services are available for ISC products - see +# http://www.isc.org for more information. +# + +CATMANPAGES = omapi.cat3 +SEDMANPAGES = omapi.man3 +SRC = protocol.c buffer.c alloc.c result.c connection.c \ + listener.c dispatch.c generic.c support.c handle.c message.c +OBJ = protocol.o buffer.o alloc.o result.o connection.o \ + listener.o dispatch.o generic.o support.o handle.o message.o +MAN = omapi.3 + +DEBUG = -g +INCLUDES = $(BINDINC) -I../includes +CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) + +all: libomapi.a test $(CATMANPAGES) + +test: test.o libomapi.a + $(CC) $(DEBUG) -o test test.o libomapi.a + +libomapi.a: $(OBJ) + rm -f libomapi.a + ar cruv libomapi.a $(OBJ) + $(RANLIB) libomapi.a + +install: all + for dir in $(LIBMANDIR); do \ + foo=""; \ + for bar in `echo $(DESTDIR)$${dir} |tr / ' '`; do \ + foo=$${foo}/$$bar; \ + if [ ! -d $$foo ]; then \ + mkdir $$foo; \ + chmod 755 $$foo; \ + fi; \ + done; \ + done + for man in $(MAN); do \ + prefix=`echo $$man |sed -e 's/\.[0-9]$$//'`; \ + suffix=`echo $$man |sed -e 's/.*\.\([0-9]\)$$/\1/'`; \ + $(MANINSTALL) $(MANFROM) $${prefix}.$(MANCAT)$${suffix} $(MANTO) \ + $(DESTDIR)$(LIBMANDIR)/$(prefix)$(LIBMANEXT); \ + done + +depend: + makedepend $(INCLUDES) $(PREDEFINES) $(SRCS) + +clean: + -rm -f $(OBJ) + +realclean: clean + -rm -f libdhcp.a *~ $(CATMANPAGES) $(SEDMANPAGES) + +distclean: realclean + -rm -f Makefile + +omapi.cat3: omapi.man3 + nroff -man omapi.man3 >omapi.cat3 + +omapi.man3: omapi.3 + sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ + -e "s#RUNDIR#$(VARRUN)#g" < omapi.3 >omapi.man3 + +# Dependencies (semi-automatically-generated) diff --git a/omapip/alloc.c b/omapip/alloc.c new file mode 100644 index 00000000..59a65231 --- /dev/null +++ b/omapip/alloc.c @@ -0,0 +1,443 @@ +/* alloc.c + + Functions supporting memory allocation for the object management + protocol... */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +isc_result_t omapi_object_reference (omapi_object_t **r, + omapi_object_t *h, + char *name) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: reference store into non-null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_object_dereference (omapi_object_t **h, + char *name) +{ + int outer_reference = 0; + int inner_reference = 0; + int handle_reference = 0; + int extra_references; + omapi_object_t *p; + + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: dereference of null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (ALLOCATION_DEBUGGING) + abort ("dereference of pointer with refcnt of zero!"); +#else + return ISC_R_INVALIDARG; +#endif + } + + /* See if this object's inner object refers to it, but don't + count this as a reference if we're being asked to free the + reference from the inner object. */ + if ((*h) -> inner && (*h) -> inner -> outer && + h != &((*h) -> inner -> outer)) + inner_reference = 1; + + /* Ditto for the outer object. */ + if ((*h) -> outer && (*h) -> outer -> inner && + h != &((*h) -> outer -> inner)) + outer_reference = 1; + + /* Ditto for the outer object. The code below assumes that + the only reason we'd get a dereference from the handle + table is if this function does it - otherwise we'd have to + traverse the handle table to find the address where the + reference is stored and compare against that, and we don't + want to do that if we can avoid it. */ + if ((*h) -> handle) + handle_reference = 1; + + /* If we are getting rid of the last reference other than + references to inner and outer objects, or from the handle + table, then we must examine all the objects in either + direction to see if they hold any non-inner, non-outer, + non-handle-table references. If not, we need to free the + entire chain of objects. */ + if ((*h) -> refcnt == + inner_reference + outer_reference + handle_reference + 1) { + if (inner_reference || outer_reference || handle_reference) { + /* XXX we could check for a reference from the + handle table here. */ + extra_references = 0; + for (p = (*h) -> inner; + p && !extra_references; p = p -> inner) { + extra_references += p -> refcnt - 1; + if (p -> inner) + --extra_references; + if (p -> handle) + --extra_references; + } + for (p = (*h) -> outer; + p && !extra_references; p = p -> outer) { + extra_references += p -> refcnt - 1; + if (p -> outer) + --extra_references; + if (p -> handle) + --extra_references; + } + } else + extra_references = 0; + + if (!extra_references) { + if (inner_reference) + omapi_object_dereference + (&(*h) -> inner -> outer, name); + if (outer_reference) + omapi_object_dereference + (&(*h) -> outer -> inner, name); + if ((*h) -> type -> destroy) + (*((*h) -> type -> destroy)) (*h, name); + free (*h); + } + } + *h = 0; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_buffer_new (omapi_buffer_t **h, + char *name) +{ + omapi_buffer_t *t; + isc_result_t status; + + t = (omapi_buffer_t *)malloc (sizeof *t); + if (!t) + return ISC_R_NOMEMORY; + memset (t, 0, sizeof *t); + status = omapi_buffer_reference (h, t, name); + if (status != ISC_R_SUCCESS) + free (t); + return status; +} + +isc_result_t omapi_buffer_reference (omapi_buffer_t **r, + omapi_buffer_t *h, + char *name) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: reference store into non-null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_buffer_dereference (omapi_buffer_t **h, + char *name) +{ + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: dereference of null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (ALLOCATION_DEBUGGING) + abort ("dereference of pointer with refcnt of zero!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + if (--(*h) -> refcnt == 0) + free (*h); + *h = 0; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_typed_data_new (omapi_typed_data_t **t, + omapi_datatype_t type, ...) +{ + va_list l; + omapi_typed_data_t *new; + int len; + int val; + char *s; + + va_start (l, type); + + switch (type) { + case omapi_datatype_int: + len = OMAPI_TYPED_DATA_INT_LEN; + val = va_arg (l, int); + break; + case omapi_datatype_string: + s = va_arg (l, char *); + val = strlen (s); + len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val + 1; + break; + case omapi_datatype_data: + val = va_arg (l, int); + len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val; + break; + case omapi_datatype_object: + len = OMAPI_TYPED_DATA_OBJECT_LEN; + break; + default: + return ISC_R_INVALIDARG; + } + + new = malloc (len); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, len); + + switch (type) { + case omapi_datatype_int: + new -> u.integer = val; + break; + case omapi_datatype_string: + strcpy (new -> u.buffer.value, s); + new -> u.buffer.len = val; + break; + case omapi_datatype_data: + new -> u.buffer.len = val; + break; + case omapi_datatype_object: + return omapi_object_reference (&new -> u.object, + va_arg (l, omapi_object_t *), + "omapi_datatype_new"); + break; + } + return omapi_typed_data_reference (t, new, "omapi_typed_data_new"); +} + +isc_result_t omapi_typed_data_reference (omapi_typed_data_t **r, + omapi_typed_data_t *h, + char *name) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: reference store into non-null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_typed_data_dereference (omapi_typed_data_t **h, + char *name) +{ + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: dereference of null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (ALLOCATION_DEBUGGING) + abort ("dereference of pointer with refcnt of zero!"); +#else + return ISC_R_INVALIDARG; +#endif + } + + if (--((*h) -> refcnt) <= 0 ) { + switch ((*h) -> type) { + case omapi_datatype_int: + case omapi_datatype_string: + case omapi_datatype_data: + default: + break; + case omapi_datatype_object: + omapi_object_dereference (&(*h) -> u.object, + name); + break; + } + free (*h); + } + *h = 0; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_data_string_new (omapi_data_string_t **d, + int len, char *name) +{ + omapi_data_string_t *new; + + new = malloc (OMAPI_DATA_STRING_EMPTY_SIZE + len); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, OMAPI_DATA_STRING_EMPTY_SIZE); + new -> len = len; + return omapi_data_string_reference (d, new, name); +} + +isc_result_t omapi_data_string_reference (omapi_data_string_t **r, + omapi_data_string_t *h, + char *name) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: reference store into non-null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_data_string_dereference (omapi_data_string_t **h, + char *name) +{ + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: dereference of null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (ALLOCATION_DEBUGGING) + abort ("dereference of pointer with refcnt of zero!"); +#else + return ISC_R_INVALIDARG; +#endif + } + + if (--((*h) -> refcnt) <= 0 ) { + free (*h); + } + *h = 0; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_value_new (omapi_value_t **d, + char *name) +{ + omapi_value_t *new; + + new = malloc (sizeof *new); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, sizeof *new); + return omapi_value_reference (d, new, name); +} + +isc_result_t omapi_value_reference (omapi_value_t **r, + omapi_value_t *h, + char *name) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: reference store into non-null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_value_dereference (omapi_value_t **h, + char *name) +{ + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (ALLOCATION_DEBUGGING) + abort ("%s: dereference of null pointer!", name); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (ALLOCATION_DEBUGGING) + abort ("dereference of pointer with refcnt of zero!"); +#else + return ISC_R_INVALIDARG; +#endif + } + + if (--((*h) -> refcnt) <= 0 ) { + if ((*h) -> name) + omapi_data_string_dereference (&(*h) -> name, name); + if ((*h) -> value) + omapi_typed_data_dereference (&(*h) -> value, name); + free (*h); + } + *h = 0; + return ISC_R_SUCCESS; +} + diff --git a/omapip/buffer.c b/omapip/buffer.c new file mode 100644 index 00000000..6bd2c946 --- /dev/null +++ b/omapip/buffer.c @@ -0,0 +1,396 @@ +/* buffer.c + + Buffer access functions for the object management protocol... */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +/* Make sure that at least len bytes are in the input buffer, and if not, + read enough bytes to make up the difference. */ + +isc_result_t omapi_connection_reader (omapi_object_t *h) +{ + omapi_buffer_t *buffer; + isc_result_t status; + int read_len, read_status; + omapi_connection_object_t *c; + int bytes_to_read; + + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + /* Make sure c -> bytes_needed is valid. */ + if (c -> bytes_needed < 0) + return ISC_R_INVALIDARG; + + /* See if there are enough bytes. */ + if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 && + c -> in_bytes > c -> bytes_needed) + return ISC_R_SUCCESS; + + if (c -> inbufs) { + for (buffer = c -> inbufs; buffer -> next; + buffer = buffer -> next) + ; + if (!BUFFER_BYTES_AVAIL (buffer)) { + status = omapi_buffer_new (&buffer -> next, + "omapi_private_read"); + if (status != ISC_R_SUCCESS) + return status; + buffer = buffer -> next; + } + } else { + status = omapi_buffer_new (&c -> inbufs, + "omapi_private_read"); + if (status != ISC_R_SUCCESS) + return status; + buffer = c -> inbufs; + } + + bytes_to_read = BUFFER_BYTES_AVAIL (buffer); + + while (bytes_to_read) { + if (buffer -> tail >= buffer -> head) + read_len = sizeof (buffer -> buf) - buffer -> tail - 1; + else + read_len = buffer -> tail - buffer -> head - 1; + + read_status = read (c -> socket, + &buffer -> buf [buffer -> tail], read_len); + if (read_status < 0) { + if (errno == EWOULDBLOCK) + return ISC_R_NOMORE; + else if (errno == EIO) + return ISC_R_IOERROR; + else if (errno == EINVAL) + return ISC_R_INVALIDARG; + else if (errno == ECONNRESET) { + omapi_disconnect (h, 0); + return ISC_R_SHUTTINGDOWN; + } else + return ISC_R_UNEXPECTED; + } + if (read_status == 0) { + omapi_disconnect (h, 0); + return ISC_R_SHUTTINGDOWN; + } + buffer -> tail += read_status; + c -> in_bytes += read_status; + if (buffer -> tail == sizeof buffer -> buf) + buffer -> tail = 0; + if (read_status < read_len) + break; + bytes_to_read -= read_status; + } + + if (c -> bytes_needed >= c -> in_bytes) { + omapi_signal (h, "ready", c); + } + return ISC_R_SUCCESS; +} + +/* Put some bytes into the output buffer for a connection. */ + +isc_result_t omapi_connection_copyin (omapi_object_t *h, + unsigned char *bufp, + int len) +{ + omapi_buffer_t *buffer; + isc_result_t status; + int bytes_copied = 0; + int copy_len; + omapi_connection_object_t *c; + + /* Make sure len is valid. */ + if (len < 0) + return ISC_R_INVALIDARG; + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + if (c -> outbufs) { + for (buffer = c -> outbufs; + buffer -> next; buffer = buffer -> next) + ; + } else { + status = omapi_buffer_new (&c -> outbufs, + "omapi_private_buffer_copyin"); + if (status != ISC_R_SUCCESS) + return status; + buffer = c -> outbufs; + } + + while (bytes_copied < len) { + /* If there is no space available in this buffer, + allocate a new one. */ + if (!BUFFER_BYTES_AVAIL (buffer)) { + status = (omapi_buffer_new + (&buffer -> next, + "omapi_private_buffer_copyin")); + if (status != ISC_R_SUCCESS) + return status; + buffer = buffer -> next; + } + + if (buffer -> tail < buffer -> head) + copy_len = buffer -> tail - buffer -> head - 1; + else + copy_len = sizeof (buffer -> buf) - buffer -> tail - 1; + if (copy_len > (len - bytes_copied)) + copy_len = len - bytes_copied; + + memcpy (&buffer -> buf [buffer -> tail], + &bufp [bytes_copied], copy_len); + buffer -> tail += copy_len; + c -> out_bytes += copy_len; + bytes_copied += copy_len; + if (buffer -> tail == sizeof buffer -> buf) + buffer -> tail = 0; + } + return ISC_R_SUCCESS; +} + +/* Copy some bytes from the input buffer, and advance the input buffer + pointer beyond the bytes copied out. */ + +u_int32_t omapi_connection_copyout (unsigned char *buf, + omapi_object_t *h, + int size) +{ + int bytes_remaining; + int bytes_this_copy; + omapi_buffer_t *buffer; + unsigned char *bufp; + omapi_connection_object_t *c; + + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + if (size > c -> in_bytes) + return ISC_R_NOMORE; + bufp = buf; + bytes_remaining = size; + buffer = c -> inbufs; + + while (bytes_remaining) { + if (!buffer) + return ISC_R_UNEXPECTED; + if (buffer -> head != buffer -> tail) { + if (buffer -> head > buffer -> tail) { + bytes_this_copy = (sizeof buffer -> buf - + buffer -> head); + } else { + bytes_this_copy = + buffer -> tail - buffer -> head; + } + if (bytes_this_copy > bytes_remaining) + bytes_this_copy = bytes_remaining; + if (bufp) { + memcpy (bufp, &buffer -> buf [buffer -> head], + bytes_this_copy); + bufp += bytes_this_copy; + } + bytes_remaining -= bytes_this_copy; + buffer -> head += bytes_this_copy; + if (buffer -> head == sizeof buffer -> buf) + buffer -> head = 0; + c -> in_bytes -= bytes_this_copy; + } + + if (buffer -> head == buffer -> tail) + buffer = buffer -> next; + } + + /* Get rid of any input buffers that we emptied. */ + buffer = (omapi_buffer_t *)0; + while (c -> inbufs && + c -> inbufs -> head == c -> inbufs -> tail) { + if (c -> inbufs -> next) { + omapi_buffer_reference + (&buffer, + c -> inbufs -> next, + "omapi_private_buffer_copyout"); + omapi_buffer_dereference + (&c -> inbufs -> next, + "omapi_private_buffer_copyout"); + } + omapi_buffer_dereference (&c -> inbufs, + "omapi_private_buffer_copyout"); + omapi_buffer_reference (&c -> inbufs, + buffer, + "omapi_private_buffer_copyout"); + omapi_buffer_dereference (&buffer, + "omapi_private_buffer_copyout"); + } + return ISC_R_SUCCESS; +} + +u_int32_t omapi_connection_writer (omapi_object_t *h) +{ + int bytes_this_write; + int bytes_written; + omapi_buffer_t *buffer; + unsigned char *bufp; + omapi_connection_object_t *c; + + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + /* Already flushed... */ + if (!c -> out_bytes) + return ISC_R_SUCCESS; + + buffer = c -> outbufs; + + while (c -> out_bytes) { + if (!buffer) + return ISC_R_UNEXPECTED; + if (buffer -> head != buffer -> tail) { + if (buffer -> head > buffer -> tail) { + bytes_this_write = (sizeof buffer -> buf - + buffer -> head); + } else { + bytes_this_write = + (buffer -> tail - buffer -> head); + } + bytes_written = write (c -> socket, + &buffer -> buf [buffer -> head], + bytes_this_write); + /* If the write failed with EWOULDBLOCK or we wrote + zero bytes, a further write would block, so we have + flushed as much as we can for now. Other errors + are really errors. */ + if (bytes_written < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) + return ISC_R_SUCCESS; + else if (errno == EPIPE) + return ISC_R_NOCONN; + else if (errno == EFBIG || errno == EDQUOT) + return ISC_R_NORESOURCES; + else if (errno == ENOSPC) + return ISC_R_NOSPACE; + else if (errno == EIO) + return ISC_R_IOERROR; + else if (errno == EINVAL) + return ISC_R_INVALIDARG; + else if (errno == ECONNRESET) + return ISC_R_SHUTTINGDOWN; + else + return ISC_R_UNEXPECTED; + } + if (bytes_written == 0) + return ISC_R_SUCCESS; + + buffer -> head += bytes_written; + if (buffer -> head == sizeof buffer -> buf) + buffer -> head = 0; + c -> out_bytes -= bytes_written; + + /* If we didn't finish out the write, we filled the + O.S. output buffer and a further write would block, + so stop trying to flush now. */ + if (bytes_written != bytes_this_write) + return ISC_R_SUCCESS; + } + + if (buffer -> head == buffer -> tail) + buffer = buffer -> next; + } + + /* Get rid of any output buffers we emptied. */ + buffer = (omapi_buffer_t *)0; + while (c -> outbufs && + c -> outbufs -> head == c -> outbufs -> tail) { + if (c -> outbufs -> next) { + omapi_buffer_reference + (&buffer, c -> outbufs -> next, + "omapi_private_flush"); + omapi_buffer_dereference + (&c -> outbufs -> next, "omapi_private_flush"); + } + omapi_buffer_dereference (&c -> outbufs, + "omapi_private_flush"); + if (buffer) { + omapi_buffer_reference (&c -> outbufs, buffer, + "omapi_private_flush"); + omapi_buffer_dereference (&buffer, + "omapi_private_flush"); + } + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_get_uint32 (omapi_object_t *c, + u_int32_t *result) +{ + u_int32_t inbuf; + isc_result_t status; + + status = omapi_connection_copyout ((unsigned char *)&inbuf, + c, sizeof inbuf); + if (status != ISC_R_SUCCESS) + return status; + + *result = ntohl (inbuf); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_put_uint32 (omapi_object_t *c, + u_int32_t value) +{ + u_int32_t inbuf; + isc_result_t status; + + inbuf = htonl (value); + + return omapi_connection_copyin (c, (unsigned char *)&inbuf, + sizeof inbuf); +} + +isc_result_t omapi_connection_get_uint16 (omapi_object_t *c, + u_int16_t *result) +{ + u_int16_t inbuf; + isc_result_t status; + + status = omapi_connection_copyout ((unsigned char *)&inbuf, + c, sizeof inbuf); + if (status != ISC_R_SUCCESS) + return status; + + *result = ntohs (inbuf); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_put_uint16 (omapi_object_t *c, + u_int16_t value) +{ + u_int16_t inbuf; + isc_result_t status; + + inbuf = htons (value); + + return omapi_connection_copyin (c, (unsigned char *)&inbuf, + sizeof inbuf); +} + diff --git a/omapip/connection.c b/omapip/connection.c new file mode 100644 index 00000000..48cdd7c6 --- /dev/null +++ b/omapip/connection.c @@ -0,0 +1,360 @@ +/* connection.c + + Subroutines for dealing with connections. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +isc_result_t omapi_connect (omapi_object_t *c, + char *server_name, + int port) +{ + struct hostent *he; + int hix; + isc_result_t status; + omapi_connection_object_t *obj; + + obj = (omapi_connection_object_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + obj -> refcnt = 1; + obj -> type = omapi_type_connection; + + status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj, + "omapi_protocol_connect"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_connect"); + return status; + } + status = omapi_object_reference (&obj -> inner, c, + "omapi_protocol_connect"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_connect"); + return status; + } + + /* Set up all the constants in the address... */ + obj -> remote_addr.sin_port = htons (port); + + /* First try for a numeric address, since that's easier to check. */ + if (!inet_aton (server_name, &obj -> remote_addr.sin_addr)) { + /* If we didn't get a numeric address, try for a domain + name. It's okay for this call to block. */ + he = gethostbyname (server_name); + if (!he) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_connect"); + return ISC_R_HOSTUNKNOWN; + } + hix = 1; + memcpy (&obj -> remote_addr.sin_addr, + he -> h_addr_list [0], + sizeof obj -> remote_addr.sin_addr); + } else + he = (struct hostent *)0; + + obj -> remote_addr.sin_len = + sizeof (struct sockaddr_in); + obj -> remote_addr.sin_family = AF_INET; + memset (&(obj -> remote_addr.sin_zero), 0, + sizeof obj -> remote_addr.sin_zero); + + /* Create a socket on which to communicate. */ + obj -> socket = + socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (obj -> socket < 0) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_connect"); + if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) + return ISC_R_NORESOURCES; + return ISC_R_UNEXPECTED; + } + + /* Try to connect to the one IP address we were given, or any of + the IP addresses listed in the host's A RR. */ + while (connect (obj -> socket, + ((struct sockaddr *) + &obj -> remote_addr), + sizeof obj -> remote_addr)) { + if (!he || !he -> h_addr_list [hix]) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_connect"); + if (errno == ECONNREFUSED) + return ISC_R_CONNREFUSED; + if (errno == ENETUNREACH) + return ISC_R_NETUNREACH; + return ISC_R_UNEXPECTED; + } + memcpy (&obj -> remote_addr.sin_addr, + he -> h_addr_list [hix++], + sizeof obj -> remote_addr.sin_addr); + } + + obj -> state = omapi_connection_connected; + + /* I don't know why this would fail, so I'm tempted not to test + the return value. */ + hix = sizeof (obj -> local_addr); + if (getsockname (obj -> socket, + ((struct sockaddr *) + &obj -> local_addr), &hix) < 0) { + } + + if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_connect"); + return ISC_R_UNEXPECTED; + } + + status = omapi_register_io_object ((omapi_object_t *)obj, + omapi_connection_readfd, + omapi_connection_writefd, + omapi_connection_reader, + omapi_connection_writer, + omapi_connection_reaper); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_connect"); + return status; + } + + return ISC_R_SUCCESS; +} + +/* Disconnect a connection object from the remote end. If force is nonzero, + close the connection immediately. Otherwise, shut down the receiving end + but allow any unsent data to be sent before actually closing the socket. */ + +isc_result_t omapi_disconnect (omapi_object_t *h, + int force) +{ + omapi_connection_object_t *c; + + c = (omapi_connection_object_t *)h; + if (c -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + if (!force) { + /* If we're already disconnecting, we don't have to do + anything. */ + if (c -> state == omapi_connection_disconnecting) + return ISC_R_SUCCESS; + + /* Try to shut down the socket - this sends a FIN to the + remote end, so that it won't send us any more data. If + the shutdown succeeds, and we still have bytes left to + write, defer closing the socket until that's done. */ + if (!shutdown (c -> socket, SHUT_RD)) { + if (c -> out_bytes > 0) { + c -> state = omapi_connection_disconnecting; + return ISC_R_SUCCESS; + } + } + } + close (c -> socket); + c -> state = omapi_connection_closed; + + /* Disconnect from I/O object, if any. */ + if (h -> outer) + omapi_object_dereference (&h -> outer, "omapi_disconnect"); + + /* If whatever created us registered a signal handler, send it + a disconnect signal. */ + omapi_signal (h, "disconnect", h); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_require (omapi_object_t *h, int bytes) +{ + omapi_connection_object_t *c; + + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + c -> bytes_needed = bytes; + if (c -> bytes_needed <= c -> in_bytes) { + return ISC_R_SUCCESS; + } + return ISC_R_NOTYET; +} + +/* Return the socket on which the dispatcher should wait for readiness + to read, for a connection object. If we already have more bytes than + we need to do the next thing, and we have at least a single full input + buffer, then don't indicate that we're ready to read. */ +int omapi_connection_readfd (omapi_object_t *h) +{ + omapi_connection_object_t *c; + if (h -> type != omapi_type_connection) + return -1; + c = (omapi_connection_object_t *)h; + if (c -> state != omapi_connection_connected) + return -1; + if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 && + c -> in_bytes > c -> bytes_needed) + return -1; + return c -> socket; +} + +/* Return the socket on which the dispatcher should wait for readiness + to write, for a connection object. If there are no bytes buffered + for writing, then don't indicate that we're ready to write. */ +int omapi_connection_writefd (omapi_object_t *h) +{ + omapi_connection_object_t *c; + if (h -> type != omapi_type_connection) + return -1; + if (c -> out_bytes) + return c -> socket; + else + return -1; +} + +/* Reaper function for connection - if the connection is completely closed, + reap it. If it's in the disconnecting state, there were bytes left + to write when the user closed it, so if there are now no bytes left to + write, we can close it. */ +isc_result_t omapi_connection_reaper (omapi_object_t *h) +{ + omapi_connection_object_t *c; + + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + c = (omapi_connection_object_t *)h; + if (c -> state == omapi_connection_disconnecting && + c -> out_bytes == 0) + omapi_disconnect (h, 1); + if (c -> state == omapi_connection_closed) + return ISC_R_NOTCONNECTED; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_connection_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_connection_destroy (omapi_object_t *h, char *name) +{ + omapi_connection_object_t *c; + + if (h -> type != omapi_type_connection) + return ISC_R_UNEXPECTED; + c = (omapi_connection_object_t *)(h); + if (c -> state == omapi_connection_connected) + omapi_disconnect (h, 1); + if (c -> listener) + omapi_object_dereference (&c -> listener, name); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_signal_handler (omapi_object_t *h, + char *name, va_list ap) +{ + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_connection_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *m) +{ + int i; + + if (m -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + if (m -> inner && m -> inner -> type -> stuff_values) + return (*(m -> inner -> type -> stuff_values)) (c, id, + m -> inner); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_write_typed_data (omapi_object_t *c, + omapi_typed_data_t *data) +{ + isc_result_t status; + omapi_handle_t handle; + + switch (data -> type) { + case omapi_datatype_int: + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + return omapi_connection_put_uint32 (c, data -> u.integer); + + case omapi_datatype_string: + case omapi_datatype_data: + status = omapi_connection_put_uint32 (c, data -> u.buffer.len); + if (status != ISC_R_SUCCESS) + return status; + return omapi_connection_copyin (c, data -> u.buffer.value, + data -> u.buffer.len); + + case omapi_datatype_object: + status = omapi_object_handle (&handle, + data -> u.object); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof handle); + if (status != ISC_R_SUCCESS) + return status; + return omapi_connection_put_uint32 (c, handle); + + } + return ISC_R_INVALIDARG; +} + diff --git a/omapip/dispatch.c b/omapip/dispatch.c new file mode 100644 index 00000000..b7a666fd --- /dev/null +++ b/omapip/dispatch.c @@ -0,0 +1,379 @@ +/* dispatch.c + + I/O dispatcher. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +static omapi_io_object_t omapi_io_states; +u_int32_t cur_time; + +/* Register an I/O handle so that we can do asynchronous I/O on it. */ + +isc_result_t omapi_register_io_object (omapi_object_t *h, + int (*readfd) (omapi_object_t *), + int (*writefd) (omapi_object_t *), + isc_result_t (*reader) + (omapi_object_t *), + isc_result_t (*writer) + (omapi_object_t *), + isc_result_t (*reaper) + (omapi_object_t *)) +{ + isc_result_t status; + omapi_io_object_t *obj, *p; + + /* omapi_io_states is a static object. If its reference count + is zero, this is the first I/O handle to be registered, so + we need to initialize it. Because there is no inner or outer + pointer on this object, and we're setting its refcnt to 1, it + will never be freed. */ + if (!omapi_io_states.refcnt) { + omapi_io_states.refcnt = 1; + omapi_io_states.type = omapi_type_io_object; + } + + obj = malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + + obj -> refcnt = 1; + obj -> type = omapi_type_io_object; + + status = omapi_object_reference (&obj -> inner, h, + "omapi_register_io_object"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_register_io_object"); + return status; + } + + status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, + "omapi_register_io_object"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_register_io_object"); + return status; + } + + /* Find the last I/O state, if there are any. */ + for (p = omapi_io_states.next; + p && p -> next; p = p -> next) + ; + if (p) + p -> next = obj; + else + omapi_io_states.next = obj; + + obj -> readfd = readfd; + obj -> writefd = writefd; + obj -> reader = reader; + obj -> writer = writer; + obj -> reaper = reaper; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_dispatch (struct timeval *t) +{ + return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states, + t); +} + +isc_result_t omapi_wait_for_completion (omapi_object_t *object, + struct timeval *t) +{ + isc_result_t status; + omapi_waiter_object_t *waiter; + omapi_object_t *inner; + + if (object) { + waiter = malloc (sizeof *waiter); + if (!waiter) + return ISC_R_NOMEMORY; + memset (waiter, 0, sizeof *waiter); + waiter -> refcnt = 1; + waiter -> type = omapi_type_waiter; + + /* Paste the waiter object onto the inner object we're + waiting on. */ + for (inner = object; inner -> inner; inner = inner -> inner) + ; + + status = omapi_object_reference (&waiter -> outer, inner, + "omapi_wait_for_completion"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&waiter, + "omapi_wait_for_completion"); + return status; + } + + status = omapi_object_reference (&inner -> inner, + (omapi_object_t *)waiter, + "omapi_wait_for_completion"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&waiter, + "omapi_wait_for_completion"); + return status; + } + } else + waiter = (omapi_waiter_object_t *)0; + + do { + status = omapi_one_dispatch (waiter, t); + if (status != ISC_R_SUCCESS) + return status; + } while (!waiter || !waiter -> ready); + + omapi_object_dereference ((omapi_object_t **)&waiter, + "omapi_wait_for_completion"); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_one_dispatch (omapi_waiter_object_t *waiter, + struct timeval *t) +{ + fd_set r, w, x; + int max = 0; + int count; + int desc; + struct timeval now, to; + omapi_io_object_t *io, *prev; + isc_result_t status; + + FD_ZERO (&x); + + /* First, see if the timeout has expired, and if so return. */ + if (t) { + gettimeofday (&now, (struct timezone *)0); + cur_time = now.tv_sec; + if (now.tv_sec > t -> tv_sec || + (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec)) + return ISC_R_TIMEDOUT; + + /* We didn't time out, so figure out how long until + we do. */ + to.tv_sec = t -> tv_sec - now.tv_sec; + to.tv_usec = t -> tv_usec - now.tv_usec; + if (to.tv_usec < 0) { + to.tv_usec += 1000000; + to.tv_sec--; + } + } + + /* If the object we're waiting on has reached completion, + return now. */ + if (waiter && waiter -> ready) + return ISC_R_SUCCESS; + + /* If we have no I/O state, we can't proceed. */ + if (!(io = omapi_io_states.next)) + return ISC_R_NOMORE; + + /* Set up the read and write masks. */ + FD_ZERO (&r); + FD_ZERO (&w); + + for (; io; io = io -> next) { + /* Check for a read socket. If we shouldn't be + trying to read for this I/O object, either there + won't be a readfd function, or it'll return -1. */ + if (io -> readfd && + (desc = (*(io -> readfd)) (io -> inner)) >= 0) { + FD_SET (desc, &r); + if (desc > max) + max = desc; + } + + /* Same deal for write fdets. */ + if (io -> writefd && + (desc = (*(io -> writefd)) (io -> inner)) >= 0) { + FD_SET (desc, &w); + if (desc > max) + max = desc; + } + } + + /* Wait for a packet or a timeout... XXX */ + count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0); + + /* Get the current time... */ + gettimeofday (&now, (struct timezone *)0); + cur_time = now.tv_sec; + + /* Not likely to be transitory... */ + if (count < 0) + return ISC_R_UNEXPECTED; + + for (io = omapi_io_states.next; io; io = io -> next) { + /* Check for a read descriptor, and if there is one, + see if we got input on that socket. */ + if (io -> readfd && + (desc = (*(io -> readfd)) (io -> inner)) >= 0) { + if (FD_ISSET (desc, &r)) + status = ((*(io -> reader)) (io -> inner)); + /* XXX what to do with status? */ + } + + /* Same deal for write descriptors. */ + if (io -> writefd && + (desc = (*(io -> writefd)) (io -> inner)) >= 0) + { + if (FD_ISSET (desc, &w)) + status = ((*(io -> writer)) (io -> inner)); + /* XXX what to do with status? */ + } + } + + /* Now check for I/O handles that are no longer valid, + and remove them from the list. */ + prev = (omapi_io_object_t *)0; + for (io = omapi_io_states.next; io; io = io -> next) { + if (io -> reaper) { + status = (*(io -> reaper)) (io -> inner); + if (status != ISC_R_SUCCESS) { + omapi_io_object_t *tmp = + (omapi_io_object_t *)0; + /* Save a reference to the next + pointer, if there is one. */ + if (io -> next) + omapi_object_reference + ((omapi_object_t **)&tmp, + (omapi_object_t *)io -> next, + "omapi_wfc"); + if (prev) { + omapi_object_dereference + (((omapi_object_t **) + &prev -> next), "omapi_wfc"); + if (tmp) + omapi_object_reference + (((omapi_object_t **) + &prev -> next), + (omapi_object_t *)tmp, + "omapi_wfc"); + } else { + omapi_object_dereference + (((omapi_object_t **) + &omapi_io_states.next), + "omapi_wfc"); + if (tmp) + omapi_object_reference + (((omapi_object_t **) + &omapi_io_states.next), + (omapi_object_t *)tmp, + "omapi_wfc"); + else + omapi_signal_in + ((omapi_object_t *) + &omapi_io_states, + "ready"); + } + if (tmp) + omapi_object_dereference + ((omapi_object_t **)&tmp, + "omapi_wfc"); + } + } + prev = io; + } + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_io_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_io_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_io_destroy (omapi_object_t *h, char *name) +{ + if (h -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_io_signal_handler (omapi_object_t *h, + char *name, va_list ap) +{ + if (h -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_io_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *i) +{ + if (i -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + + if (i -> inner && i -> inner -> type -> stuff_values) + return (*(i -> inner -> type -> stuff_values)) (c, id, + i -> inner); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_waiter_signal_handler (omapi_object_t *h, + char *name, va_list ap) +{ + omapi_waiter_object_t *waiter; + + if (h -> type != omapi_type_waiter) + return ISC_R_INVALIDARG; + + if (!strcmp (name, "ready")) { + waiter = (omapi_waiter_object_t *)h; + waiter -> ready = 1; + return ISC_R_SUCCESS; + } + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + diff --git a/omapip/generic.c b/omapip/generic.c new file mode 100644 index 00000000..6c1ac3ce --- /dev/null +++ b/omapip/generic.c @@ -0,0 +1,249 @@ +/* generic.c + + Subroutines that support the generic object. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +isc_result_t omapi_generic_new (omapi_object_t **gen, char *name) +{ + omapi_generic_object_t *obj; + + obj = malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + obj -> refcnt = 0; + obj -> type = omapi_type_generic; + + return omapi_object_reference (gen, (omapi_object_t *)obj, name); +} + +isc_result_t omapi_generic_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + omapi_generic_object_t *g; + omapi_value_t *new; + omapi_value_t **va; + int vm_new; + int i; + isc_result_t status; + + if (h -> type != omapi_type_generic) + return ISC_R_INVALIDARG; + g = (omapi_generic_object_t *)h; + + /* See if there's already a value with this name attached to + the generic object, and if so, replace the current value + with the new one. */ + for (i = 0; i < g -> nvalues; i++) { + if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { + /* There's an inconsistency here: the standard + behaviour of a set_values method when + passed a matching name and a null value is + to delete the value associated with that + name (where possible). In the generic + object, we remember the name/null pair, + because generic objects are generally used + to pass messages around, and this is the + way that remote entities delete values from + local objects. If the get_value method of + a generic object is called for a name that + maps to a name/null pair, ISC_R_NOTFOUND is + returned. */ + new = (omapi_value_t *)0; + status = (omapi_value_new (&new, + "omapi_message_get_value")); + if (status != ISC_R_SUCCESS) + return status; + omapi_data_string_reference + (&new -> name, name, + "omapi_message_get_value"); + if (value) + omapi_typed_data_reference + (&new -> value, value, + "omapi_generic_set_value"); + + omapi_value_dereference (&(g -> values [i]), + "omapi_message_set_value"); + status = (omapi_value_reference + (&(g -> values [i]), new, + "omapi_message_set_value")); + omapi_value_dereference (&new, + "omapi_message_set_value"); + return status; + } + } + + /* If the name isn't already attached to this object, see if an + inner object has it. */ + if (h -> inner && h -> inner -> type -> set_value) + status = ((*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value)); + if (status != ISC_R_NOTFOUND) + return status; + + /* Okay, so it's a value that no inner object knows about, and + (implicitly, since the outer object set_value method would + have called this object's set_value method) it's an object that + no outer object knows about, it's this object's responsibility + to remember it - that's what generic objects do. */ + + /* Arrange for there to be space for the pointer to the new + name/value pair if necessary: */ + if (g -> nvalues == g -> va_max) { + if (g -> va_max) + vm_new = 2 * g -> va_max; + else + vm_new = 10; + va = malloc (vm_new * sizeof *va); + if (!va) + return ISC_R_NOMEMORY; + if (g -> va_max) + memcpy (va, g -> values, g -> va_max * sizeof *va); + memset (va + g -> va_max, 0, + (vm_new - g -> va_max) * sizeof *va); + free (g -> values); + g -> values = va; + } + status = omapi_value_new (&g -> values [g -> nvalues], + "omapi_generic_set_value"); + if (status != ISC_R_SUCCESS) + return status; + omapi_data_string_reference (&g -> values [g -> nvalues] -> name, name, + "omapi_generic_set_value"); + if (value) + omapi_typed_data_reference + (&g -> values [g -> nvalues] -> value, value, + "omapi_generic_set_value"); + g -> nvalues++; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_generic_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + int i; + omapi_generic_object_t *g; + + if (h -> type != omapi_type_generic) + return ISC_R_INVALIDARG; + g = (omapi_generic_object_t *)h; + + /* Look up the specified name in our list of objects. */ + for (i = 0; i < g -> nvalues; i++) { + if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { + /* If this is a name/null value pair, this is the + same as if there were no value that matched + the specified name, so return ISC_R_NOTFOUND. */ + if (!g -> values [i] -> value) + return ISC_R_NOTFOUND; + /* Otherwise, return the name/value pair. */ + return omapi_value_reference + (value, g -> values [i], + "omapi_message_get_value"); + } + } + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_generic_destroy (omapi_object_t *h, char *name) +{ + omapi_generic_object_t *g; + int i; + + if (h -> type != omapi_type_generic) + return ISC_R_UNEXPECTED; + g = (omapi_generic_object_t *)h; + + if (g -> values) { + for (i = 0; i < g -> nvalues; i++) { + if (g -> values [i]) + omapi_value_dereference (&g -> values [i], + name); + } + free (g -> values); + g -> values = (omapi_value_t **)0; + g -> va_max = 0; + } + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_generic_signal_handler (omapi_object_t *h, + char *name, va_list ap) +{ + if (h -> type != omapi_type_generic) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_generic_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *g) +{ + omapi_generic_object_t *src; + int i; + isc_result_t status; + + if (g -> type != omapi_type_generic) + return ISC_R_INVALIDARG; + src = (omapi_generic_object_t *)g; + + for (i = 0; i < src -> nvalues; i++) { + if (src -> values [i] && src -> values [i] -> name -> len) { + status = (omapi_connection_put_uint16 + (c, src -> values [i] -> name -> len)); + if (status != ISC_R_SUCCESS) + return status; + status = (omapi_connection_copyout + (src -> values [i] -> name -> value, c, + src -> values [i] -> name -> len)); + if (status != ISC_R_SUCCESS) + return status; + + status = (omapi_connection_write_typed_data + (c, src -> values [i] -> value)); + if (status != ISC_R_SUCCESS) + return status; + } + } + + if (g -> inner && g -> inner -> type -> stuff_values) + return (*(g -> inner -> type -> stuff_values)) (c, id, + g -> inner); + return ISC_R_SUCCESS; +} + diff --git a/omapip/handle.c b/omapip/handle.c new file mode 100644 index 00000000..35d30ac3 --- /dev/null +++ b/omapip/handle.c @@ -0,0 +1,265 @@ +/* handle.c + + Functions for maintaining handles on objects. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +/* The handle table is a hierarchical tree designed for quick mapping + of handle identifiers to objects. Objects contain their own handle + identifiers if they have them, so the reverse mapping is also + quick. The hierarchy is made up of table objects, each of which + has 120 entries, a flag indicating whether the table is a leaf + table or an indirect table, the handle of the first object covered + by the table and the first object after that that's *not* covered + by the table, a count of how many objects of either type are + currently stored in the table, and an array of 120 entries pointing + either to objects or tables. + + When we go to add an object to the table, we look to see if the + next object handle to be assigned is covered by the outermost + table. If it is, we find the place within that table where the + next handle should go, and if necessary create additional nodes in + the tree to contain the new handle. The pointer to the object is + then stored in the correct position. + + Theoretically, we could have some code here to free up handle + tables as they go out of use, but by and large handle tables won't + go out of use, so this is being skipped for now. It shouldn't be + too hard to implement in the future if there's a different + application. */ + +omapi_handle_table_t *omapi_handle_table; +omapi_handle_t omapi_next_handle = 1; /* Next handle to be assigned. */ + +static isc_result_t omapi_handle_lookup_in (omapi_object_t **, + omapi_handle_t, + omapi_handle_table_t *); +static isc_result_t omapi_object_handle_in_table (omapi_handle_t, + omapi_handle_table_t *, + omapi_object_t *); +static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **); + +isc_result_t omapi_object_handle (omapi_handle_t *h, omapi_object_t *o) +{ + int tabix; + isc_result_t status; + + if (o -> handle) { + *h = o -> handle; + return ISC_R_SUCCESS; + } + + if (!omapi_handle_table) { + omapi_handle_table = malloc (sizeof *omapi_handle_table); + if (!omapi_handle_table) + return ISC_R_NOMEMORY; + memset (omapi_handle_table, 0, sizeof *omapi_handle_table); + omapi_handle_table -> first = 0; + omapi_handle_table -> limit = OMAPI_HANDLE_TABLE_SIZE; + omapi_handle_table -> leafp = 1; + } + + /* If this handle doesn't fit in the outer table, we need to + make a new outer table. This is a while loop in case for + some reason we decide to do disjoint handle allocation, + where the next level of indirection still isn't big enough + to enclose the next handle ID. */ + + while (omapi_next_handle >= omapi_handle_table -> limit) { + omapi_handle_table_t *new; + + new = malloc (sizeof *new); + if (!new) + return ISC_R_NOMEMORY; + memset (omapi_handle_table, 0, sizeof *omapi_handle_table); + new -> first = 0; + new -> limit = (omapi_handle_table -> limit * + OMAPI_HANDLE_TABLE_SIZE); + new -> leafp = 0; + new -> children [0].table = omapi_handle_table; + omapi_handle_table = new; + } + + /* Try to cram this handle into the existing table. */ + status = omapi_object_handle_in_table (omapi_next_handle, + omapi_handle_table, o); + /* If it worked, return the next handle and increment it. */ + if (status == ISC_R_SUCCESS) { + *h = omapi_next_handle; + omapi_next_handle++; + return ISC_R_SUCCESS; + } + if (status != ISC_R_NOSPACE) + return status; + + status = omapi_handle_table_enclose (&omapi_handle_table); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_handle_in_table (omapi_next_handle, + omapi_handle_table, o); + if (status != ISC_R_SUCCESS) + return status; + *h = omapi_next_handle; + omapi_next_handle++; + + return ISC_R_SUCCESS; +} + +static isc_result_t omapi_object_handle_in_table (omapi_handle_t h, + omapi_handle_table_t *table, + omapi_object_t *o) +{ + omapi_handle_table_t *inner; + omapi_handle_t scale, index; + isc_result_t status; + + if (table -> first > h || table -> limit <= h) + return ISC_R_NOSPACE; + + /* If this is a leaf table, just stash the object in the + appropriate place. */ + if (table -> leafp) { + status = (omapi_object_reference + (&table -> children [h - table -> first].object, + o, "omapi_object_handle_in_table")); + if (status != ISC_R_SUCCESS) + return status; + o -> handle = h; + return ISC_R_SUCCESS; + } + + /* Scale is the number of handles represented by each child of this + table. For a leaf table, scale would be 1. For a first level + of indirection, 120. For a second, 120 * 120. Et cetera. */ + scale = (table -> limit - table -> first) / OMAPI_HANDLE_TABLE_SIZE; + + /* So the next most direct table from this one that contains the + handle must be the subtable of this table whose index into this + table's array of children is the handle divided by the scale. */ + index = (h - table -> first) / scale; + inner = table -> children [index].table; + + /* If there is no more direct table than this one in the slot + we came up with, make one. */ + if (!inner) { + inner = malloc (sizeof *inner); + if (!inner) + return ISC_R_NOMEMORY; + memset (inner, 0, sizeof *inner); + inner -> first = index * scale + table -> first; + inner -> limit = inner -> first + scale; + if (scale == OMAPI_HANDLE_TABLE_SIZE) + inner -> leafp = 1; + table -> children [index].table = inner; + } + + status = omapi_object_handle_in_table (h, inner, o); + if (status == ISC_R_NOSPACE) { + status = (omapi_handle_table_enclose + (&table -> children [index].table)); + if (status != ISC_R_SUCCESS) + return status; + + return omapi_object_handle_in_table + (h, table -> children [index].table, o); + } + return status; +} + +static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **table) +{ + omapi_handle_table_t *inner = *table; + omapi_handle_table_t *new; + int index, base, scale; + + /* The scale of the table we're enclosing is going to be the + difference between its "first" and "limit" members. So the + scale of the table enclosing it is going to be that multiplied + by the table size. */ + scale = (inner -> first - inner -> limit) * OMAPI_HANDLE_TABLE_SIZE; + + /* The range that the enclosing table covers is going to be + the result of subtracting the remainder of dividing the + enclosed table's first entry number by the enclosing + table's scale. If handle IDs are being allocated + sequentially, the enclosing table's "first" value will be + the same as the enclosed table's "first" value. */ + base = inner -> first - inner -> first % scale; + + /* The index into the enclosing table at which the enclosed table + will be stored is going to be the difference between the "first" + value of the enclosing table and the enclosed table - zero, if + we are allocating sequentially. */ + index = (base - inner -> first) / OMAPI_HANDLE_TABLE_SIZE; + + new = malloc (sizeof *new); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, sizeof *new); + new -> first = base; + new -> limit = base + scale; + if (scale == OMAPI_HANDLE_TABLE_SIZE) + new -> leafp = 0; + new -> children [index].table = inner; + *table = new; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_handle_lookup (omapi_object_t **o, omapi_handle_t h) +{ + return omapi_handle_lookup_in (o, h, omapi_handle_table); +} + +static isc_result_t omapi_handle_lookup_in (omapi_object_t **o, + omapi_handle_t h, + omapi_handle_table_t *table) + +{ + omapi_handle_table_t *inner; + omapi_handle_t scale, index; + + if (!table || table -> first > h || table -> limit <= h) + return ISC_R_NOTFOUND; + + /* If this is a leaf table, just grab the object. */ + if (table -> leafp) { + /* Not there? */ + if (!table -> children [h - table -> first].object) + return ISC_R_NOTFOUND; + return omapi_object_reference + (o, table -> children [h - table -> first].object, + "omapi_handle_lookup_in"); + } + + /* Scale is the number of handles represented by each child of this + table. For a leaf table, scale would be 1. For a first level + of indirection, 120. For a second, 120 * 120. Et cetera. */ + scale = (table -> limit - table -> first) / OMAPI_HANDLE_TABLE_SIZE; + + /* So the next most direct table from this one that contains the + handle must be the subtable of this table whose index into this + table's array of children is the handle divided by the scale. */ + index = (h - table -> first) / scale; + inner = table -> children [index].table; + + return omapi_handle_lookup_in (o, h, table -> children [index].table); +} diff --git a/omapip/listener.c b/omapip/listener.c new file mode 100644 index 00000000..57da4ace --- /dev/null +++ b/omapip/listener.c @@ -0,0 +1,246 @@ +/* listener.c + + Subroutines that support the generic listener object. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +isc_result_t omapi_listen (omapi_object_t *h, + int port, + int max) +{ + struct hostent *he; + int hix; + isc_result_t status; + omapi_listener_object_t *obj; + + /* Get the handle. */ + obj = (omapi_listener_object_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + obj -> refcnt = 1; + obj -> type = omapi_type_listener; + + /* Connect this object to the inner object. */ + status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, + "omapi_protocol_listen"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_listen"); + return status; + } + status = omapi_object_reference (&obj -> inner, h, + "omapi_protocol_listen"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_listen"); + return status; + } + + /* Set up the address on which we will listen... */ + obj -> address.sin_port = htons (port); + obj -> address.sin_addr.s_addr = htonl (INADDR_ANY); + + /* Create a socket on which to listen. */ + obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (!obj -> socket) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_listen"); + if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) + return ISC_R_NORESOURCES; + return ISC_R_UNEXPECTED; + } + + /* Try to bind to the wildcard address using the port number + we were given. */ + if (bind (obj -> socket, + (struct sockaddr *)&obj -> address, sizeof obj -> address)) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_listen"); + if (errno == EADDRINUSE) + return ISC_R_ADDRNOTAVAIL; + if (errno == EPERM) + return ISC_R_NOPERM; + return ISC_R_UNEXPECTED; + } + + /* Now tell the kernel to listen for connections. */ + if (listen (obj -> socket, max)) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_listen"); + return ISC_R_UNEXPECTED; + } + + status = omapi_register_io_object ((omapi_object_t *)obj, + omapi_listener_readfd, 0, + omapi_accept, 0, 0); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_listen"); + return status; + } + + return ISC_R_SUCCESS; +} + +/* Return the socket on which the dispatcher should wait for readiness + to read, for a listener object. */ +int omapi_listener_readfd (omapi_object_t *h) +{ + omapi_listener_object_t *l; + + if (h -> type != omapi_type_listener) + return -1; + l = (omapi_listener_object_t *)h; + + return l -> socket; +} + +/* Reader callback for a listener object. Accept an incoming connection. */ +isc_result_t omapi_accept (omapi_object_t *h) +{ + isc_result_t status; + int len; + omapi_connection_object_t *obj; + omapi_listener_object_t *listener; + + if (h -> type != omapi_type_listener) + return -1; + listener = (omapi_listener_object_t *)h; + + /* Get the handle. */ + obj = (omapi_connection_object_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + obj -> refcnt = 1; + obj -> type = omapi_type_connection; + + /* Accept the connection. */ + len = sizeof obj -> remote_addr; + obj -> socket = + accept (listener -> socket, + ((struct sockaddr *) + &(obj -> remote_addr)), &len); + if (!obj -> socket) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_accept"); + if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) + return ISC_R_NORESOURCES; + return ISC_R_UNEXPECTED; + } + + obj -> state = omapi_connection_connected; + + status = omapi_register_io_object ((omapi_object_t *)obj, + omapi_connection_readfd, + omapi_connection_writefd, + omapi_connection_reader, + omapi_connection_writer, + omapi_connection_reaper); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_accept"); + return status; + } + + omapi_object_reference (&obj -> listener, (omapi_object_t *)listener, + "omapi_accept"); + + status = omapi_signal (h, "connect", obj); + + /* Lose our reference to the connection, so it'll be gc'd when it's + reaped. */ + omapi_object_dereference ((omapi_object_t **)&obj, "omapi_accept"); + return status; +} + +isc_result_t omapi_listener_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_listener_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_listener_destroy (omapi_object_t *h, char *name) +{ + omapi_listener_object_t *l; + + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + l = (omapi_listener_object_t *)(h); + + if (l -> socket != -1) { + close (l -> socket); + l -> socket = -1; + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_listener_signal_handler (omapi_object_t *h, + char *name, va_list ap) +{ + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_listener_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *l) +{ + int i; + + if (l -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + + if (l -> inner && l -> inner -> type -> stuff_values) + return (*(l -> inner -> type -> stuff_values)) (c, id, + l -> inner); + return ISC_R_SUCCESS; +} + diff --git a/omapip/message.c b/omapip/message.c new file mode 100644 index 00000000..04f23142 --- /dev/null +++ b/omapip/message.c @@ -0,0 +1,294 @@ +/* message.c + + Subroutines for dealing with message objects. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +omapi_message_object_t *omapi_registered_messages; + +isc_result_t omapi_message_new (omapi_object_t **o, char *name) +{ + omapi_message_object_t *m; + isc_result_t status; + + m = malloc (sizeof *m); + if (!m) + return ISC_R_NOMEMORY; + memset (m, 0, sizeof *m); + m -> type = omapi_type_message; + m -> refcnt = 1; + + status = omapi_object_reference (o, (omapi_object_t *)m, name); + omapi_object_dereference ((omapi_object_t **)&m, name); + return status; +} + +isc_result_t omapi_message_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + omapi_message_object_t *m; + isc_result_t status; + + if (h -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)h; + + /* Can't set authlen. */ + + /* Can set authenticator, but the value must be typed data. */ + if (!omapi_ds_strcmp (name, "authenticator")) { + if (m -> authenticator) + omapi_typed_data_dereference + (&m -> authenticator, + "omapi_message_set_value"); + omapi_typed_data_reference (&m -> authenticator, + value, + "omapi_message_set_value"); + return ISC_R_SUCCESS; + + /* Can set authid, but it has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "authid")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> authid = value -> u.integer; + + /* Can set op, but it has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "op")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> op = value -> u.integer; + + /* Handle also has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "handle")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> h = value -> u.integer; + + /* Transaction ID has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "id")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> id = value -> u.integer; + + /* Remote transaction ID has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "rid")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> rid = value -> u.integer; + } + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> set_value) { + status = ((*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS) + return status; + } + + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_message_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + omapi_message_object_t *m; + if (h -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)h; + + /* Look for values that are in the message data structure. */ + if (!omapi_ds_strcmp (name, "authlen")) + return omapi_make_int_value (value, name, m -> authlen, + "omapi_message_get_value"); + else if (!omapi_ds_strcmp (name, "authenticator")) { + if (m -> authenticator) + return omapi_make_value (value, + name, m -> authenticator, + "omapi_message_get_value"); + else + return ISC_R_NOTFOUND; + } else if (!omapi_ds_strcmp (name, "authid")) { + return omapi_make_int_value (value, name, m -> authid, + "omapi_message_get_value"); + } else if (!omapi_ds_strcmp (name, "op")) { + return omapi_make_int_value (value, name, m -> op, + "omapi_message_get_value"); + } else if (!omapi_ds_strcmp (name, "handle")) { + return omapi_make_int_value (value, name, m -> handle, + "omapi_message_get_value"); + } else if (!omapi_ds_strcmp (name, "id")) { + return omapi_make_int_value (value, name, m -> id, + "omapi_message_get_value"); + } else if (!omapi_ds_strcmp (name, "rid")) { + return omapi_make_int_value (value, name, m -> rid, + "omapi_message_get_value"); + } + + /* See if there's an inner object that has the value. */ + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_message_destroy (omapi_object_t *h, char *name) +{ + int i; + + omapi_message_object_t *m; + if (h -> type != omapi_type_message) + return ISC_R_INVALIDARG; + if (m -> authenticator) { + omapi_typed_data_dereference (&m -> authenticator, name); + } + if (!m -> prev && omapi_registered_messages != m) + omapi_message_unregister (h); + if (m -> prev) + omapi_object_dereference ((omapi_object_t **)&m -> prev, name); + if (m -> next) + omapi_object_dereference ((omapi_object_t **)&m -> next, name); + if (m -> id_object) + omapi_object_dereference ((omapi_object_t **)&m -> id_object, + name); + if (m -> object) + omapi_object_dereference ((omapi_object_t **)&m -> object, + name); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_message_signal_handler (omapi_object_t *h, + char *name, va_list ap) +{ + if (h -> type != omapi_type_message) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_message_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *m) +{ + int i; + + if (m -> type != omapi_type_message) + return ISC_R_INVALIDARG; + + if (m -> inner && m -> inner -> type -> stuff_values) + return (*(m -> inner -> type -> stuff_values)) (c, id, + m -> inner); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_message_register (omapi_object_t *mo) +{ + omapi_message_object_t *m; + + if (mo -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)mo; + + /* Already registered? */ + if (m -> prev || m -> next || omapi_registered_messages == m) + return ISC_R_INVALIDARG; + + if (omapi_registered_messages) { + omapi_object_reference + ((omapi_object_t **)&m -> next, + (omapi_object_t *)omapi_registered_messages, + "omapi_message_register"); + omapi_object_reference + ((omapi_object_t **)&omapi_registered_messages -> prev, + (omapi_object_t *)m, "omapi_message_register"); + omapi_object_dereference + ((omapi_object_t **)&omapi_registered_messages, + "omapi_message_register"); + } + omapi_object_reference + ((omapi_object_t **)&omapi_registered_messages, + (omapi_object_t *)m, "omapi_message_register"); + return ISC_R_SUCCESS;; +} + +isc_result_t omapi_message_unregister (omapi_object_t *mo) +{ + omapi_message_object_t *m; + omapi_message_object_t *n; + + if (mo -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)mo; + + /* Not registered? */ + if (!m -> prev && omapi_registered_messages != m) + return ISC_R_INVALIDARG; + + n = (omapi_message_object_t *)0; + if (m -> next) { + omapi_object_reference ((omapi_object_t **)&n, + (omapi_object_t *)m -> next, + "omapi_message_unregister"); + omapi_object_dereference ((omapi_object_t **)&m -> next, + "omapi_message_unregister"); + } + if (m -> prev) { + omapi_message_object_t *tmp = (omapi_message_object_t *)0; + omapi_object_reference ((omapi_object_t **)&tmp, + (omapi_object_t *)m -> prev, + "omapi_message_register"); + omapi_object_dereference ((omapi_object_t **)&m -> prev, + "omapi_message_unregister"); + if (tmp -> next) + omapi_object_dereference + ((omapi_object_t **)&tmp -> next, + "omapi_message_unregister"); + if (n) + omapi_object_reference + ((omapi_object_t **)&tmp -> next, + (omapi_object_t *)n, + "omapi_message_unregister"); + omapi_object_dereference ((omapi_object_t **)&tmp, + "omapi_message_unregister"); + } else { + omapi_object_dereference + ((omapi_object_t **)&omapi_registered_messages, + "omapi_unregister_message"); + if (n) + omapi_object_reference + ((omapi_object_t **)&omapi_registered_messages, + (omapi_object_t *)n, + "omapi_message_unregister"); + } + if (n) + omapi_object_dereference ((omapi_object_t **)&n, + "omapi_message_unregister"); + return ISC_R_SUCCESS; +} diff --git a/omapip/omapi.3 b/omapip/omapi.3 new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/omapip/omapi.3 diff --git a/omapip/protocol.c b/omapip/protocol.c new file mode 100644 index 00000000..f8656389 --- /dev/null +++ b/omapip/protocol.c @@ -0,0 +1,639 @@ +/* protocol.c + + Functions supporting the object management protocol... */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +isc_result_t omapi_protocol_connect (omapi_object_t *h, + char *server_name, + int port, + omapi_object_t *authinfo) +{ + isc_result_t status; + omapi_protocol_object_t *obj; + + obj = (omapi_protocol_object_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + obj -> refcnt = 1; + obj -> type = omapi_type_protocol; + + status = omapi_connect ((omapi_object_t *)obj, server_name, port); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_connect"); + return status; + } + status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, + "omapi_protocol_connect"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_connect"); + return status; + } + status = omapi_object_reference (&obj -> inner, h, + "omapi_protocol_connect"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_connect"); + return status; + } + + /* Send the introductory message. */ + status = omapi_protocol_send_intro ((omapi_object_t *)obj, + OMAPI_PROTOCOL_VERSION, + sizeof (omapi_protocol_header_t)); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_connect"); + return status; + } + + if (authinfo) + omapi_object_reference (&obj -> authinfo, authinfo, + "omapi_protocol_connect"); + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_accept"); + return ISC_R_SUCCESS; +} + +/* Send the protocol introduction message. */ +isc_result_t omapi_protocol_send_intro (omapi_object_t *h, + int ver, + int hsize) +{ + isc_result_t status; + omapi_protocol_object_t *p; + + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)h; + + if (!h -> outer || h -> outer -> type != omapi_type_connection) + return ISC_R_NOTCONNECTED; + + status = omapi_connection_put_uint32 (h -> outer, ver); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_uint32 (h -> outer, hsize); + + if (status != ISC_R_SUCCESS) + return status; + + /* Require the other end to send an intro - this kicks off the + protocol input state machine. */ + p -> state = omapi_protocol_intro_wait; + status = omapi_connection_require (h -> outer, 8); + if (status != ISC_R_SUCCESS && status != ISC_R_NOTYET) + return status; + + /* Make up an initial transaction ID for this connection. */ + p -> next_xid = random (); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_protocol_send_message (omapi_object_t *po, + omapi_object_t *id, + omapi_object_t *mo, + omapi_object_t *omo) +{ + omapi_protocol_object_t *p; + omapi_object_t *c; + omapi_message_object_t *m; + omapi_message_object_t *om; + isc_result_t status; + u_int32_t foo; + + if (po -> type != omapi_type_protocol || + !po -> outer || po -> outer -> type != omapi_type_connection || + mo -> type != omapi_type_message) + return ISC_R_INVALIDARG; + if (omo && omo -> type != omapi_type_message) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)po; + c = (omapi_object_t *)(po -> outer); + m = (omapi_message_object_t *)mo; + om = (omapi_message_object_t *)omo; + + /* XXX Write the authenticator length */ + status = omapi_connection_put_uint32 (c, 0); + if (status != ISC_R_SUCCESS) + return status; + /* XXX Write the ID of the authentication key we're using. */ + status = omapi_connection_put_uint32 (c, 0); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Write the opcode. */ + status = omapi_connection_put_uint32 (c, m -> op); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Write the handle. If we've been given an explicit handle, use + that. Otherwise, use the handle of the object we're sending. + The caller is responsible for arranging for one of these handles + to be set (or not). */ + status = omapi_connection_put_uint32 (c, (m -> h + ? m -> h + : m -> object -> handle)); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Set and write the transaction ID. */ + m -> id = p -> next_xid++; + status = omapi_connection_put_uint32 (c, m -> id); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Write the transaction ID of the message to which this is a + response, if there is such a message. */ + status = omapi_connection_put_uint32 (c, om ? om -> id : 0); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Now stuff out all the published name/value pairs associated + with the message. */ + status = omapi_stuff_values (c, id, m -> object); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Write the zero-length name that terminates the list of name/value + pairs. */ + status = omapi_connection_put_uint16 (c, 0); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* XXX Write the authenticator... */ + + return ISC_R_SUCCESS; +} + + +isc_result_t omapi_protocol_signal_handler (omapi_object_t *h, + char *name, va_list ap) +{ + isc_result_t status; + omapi_protocol_object_t *p; + omapi_object_t *c; + u_int16_t nlen; + u_int32_t vlen; + + if (h -> type != omapi_type_protocol) { + /* XXX shouldn't happen. Put an assert here? */ + return ISC_R_UNEXPECTED; + } + p = (omapi_protocol_object_t *)h; + + /* Not a signal we recognize? */ + if (strcmp (name, "ready")) { + if (p -> inner && p -> inner -> type -> signal_handler) + return (*(p -> inner -> type -> signal_handler)) (h, + name, + ap); + return ISC_R_NOTFOUND; + } + + if (!p -> outer || p -> outer -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = p -> outer; + + /* We get here because we requested that we be woken up after + some number of bytes were read, and that number of bytes + has in fact been read. */ + switch (p -> state) { + case omapi_protocol_intro_wait: + /* Get protocol version and header size in network + byte order. */ + omapi_connection_get_uint32 (c, &p -> protocol_version); + omapi_connection_get_uint32 (c, &p -> header_size); + + /* We currently only support the current protocol version. */ + if (p -> protocol_version != OMAPI_PROTOCOL_VERSION) { + omapi_disconnect (c, 1); + return ISC_R_VERSIONMISMATCH; + } + + if (p -> header_size < sizeof (omapi_protocol_header_t)) { + omapi_disconnect (c, 1); + return ISC_R_PROTOCOLERROR; + } + + status = omapi_signal_in (h -> inner, "ready"); + + to_header_wait: + /* The next thing we're expecting is a message header. */ + p -> state = omapi_protocol_header_wait; + + /* Register a need for the number of bytes in a + header, and if we already have that many, process + them immediately. */ + if ((omapi_connection_require + (c, p -> header_size)) != ISC_R_SUCCESS) + break; + /* If we already have the data, fall through. */ + + case omapi_protocol_header_wait: + status = omapi_message_new ((omapi_object_t **)&p -> message, + "omapi_protocol_signal_handler"); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* We need a generic object to hang off of the + incoming message. */ + status = omapi_generic_new (&p -> message -> object, + "omapi_protocol_signal_handler"); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Swap in the header... */ + omapi_connection_get_uint32 (c, &p -> message -> authid); + + /* XXX bind the authenticator here! */ + omapi_connection_get_uint32 (c, &p -> message -> authlen); + omapi_connection_get_uint32 (c, &p -> message -> op); + omapi_connection_get_uint32 (c, &p -> message -> handle); + omapi_connection_get_uint32 (c, &p -> message -> id); + omapi_connection_get_uint32 (c, &p -> message -> rid); + + /* If there was any extra header data, skip over it. */ + if (p -> header_size > sizeof (omapi_protocol_header_t)) { + omapi_connection_copyout + (0, c, (p -> header_size - + sizeof (omapi_protocol_header_t))); + } + + /* XXX must compute partial signature across the + XXX preceding bytes. Also, if authenticator + specifies encryption as well as signing, we may + have to decrypt the data on the way in. */ + + need_name_length: + /* The next thing we're expecting is length of the + first name. */ + p -> state = omapi_protocol_name_length_wait; + + /* Wait for a 16-bit length. */ + if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS) + break; + /* If it's already here, fall through. */ + + case omapi_protocol_name_length_wait: + omapi_connection_get_uint16 (c, &nlen); + /* A zero-length name means that we're done reading name+value + pairs. */ + if (nlen == 0) { + /* If the authenticator length is zero, there's no + signature to read in, so go straight to processing + the message. */ + if (p -> message -> authlen == 0) + goto message_done; + + /* The next thing we're expecting is the + message signature. */ + p -> state = omapi_protocol_signature_wait; + + /* Wait for the number of bytes specified for + the authenticator. If we already have it, + go read it in. */ + if (omapi_connection_require + (c, p -> message -> authlen) == ISC_R_SUCCESS) + goto signature_wait; + break; + } + + /* Allocate a buffer for the name. */ + status = (omapi_data_string_new + (&p -> name, nlen, "omapi_protocol_signal_handler")); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return ISC_R_NOMEMORY; + } + if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS) + break; + /* If it's already here, fall through. */ + + case omapi_protocol_name_wait: + omapi_connection_copyout (p -> name -> value, c, + p -> name -> len); + /* Wait for a 32-bit length. */ + if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS) + break; + /* If it's already here, fall through. */ + + case omapi_protocol_value_length_wait: + omapi_connection_get_uint32 (c, &vlen); + + /* Zero-length values are allowed - if we get one, we + don't have to read any data for the value - just + get the next one, if there is a next one. */ + if (!vlen) + goto insert_new_value; + + status = (omapi_typed_data_new + (&p -> value, omapi_datatype_data, nlen, + "omapi_protocol_signal_handler")); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return ISC_R_NOMEMORY; + } + + if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS) + break; + /* If it's already here, fall through. */ + + case omapi_protocol_value_wait: + omapi_connection_copyout (p -> value -> u.buffer.value, c, + p -> value -> u.buffer.len); + + insert_new_value: + status = (omapi_set_value + ((omapi_object_t *)p -> message -> object, + p -> message -> id_object, p -> name, p -> value)); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + omapi_data_string_dereference + (&p -> name, "omapi_protocol_signal_handler"); + omapi_typed_data_dereference (&p -> value, + "omapi_protocol_signal_handler"); + goto need_name_length; + + signature_wait: + case omapi_protocol_signature_wait: + status = omapi_typed_data_new (&p -> message -> authenticator, + omapi_datatype_data, + p -> message -> authlen); + + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return ISC_R_NOMEMORY; + } + omapi_connection_copyout + (p -> message -> authenticator -> u.buffer.value, c, + p -> message -> authlen); + /* XXX now do something to verify the signature. */ + + message_done: + /* XXX process the message. */ + /* XXX unbind the authenticator. */ + + /* Now wait for the next message. */ + goto to_header_wait; + + default: + /* XXX should never get here. Assertion? */ + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_protocol_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_protocol_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_protocol_destroy (omapi_object_t *h, char *name) +{ + omapi_protocol_object_t *p; + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)h; + if (p -> message) + omapi_object_dereference ((omapi_object_t **)&p -> message, + name); + if (p -> authinfo) + return omapi_object_dereference (&p -> authinfo, name); + return ISC_R_SUCCESS; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_protocol_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *p) +{ + int i; + + if (p -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + + if (p -> inner && p -> inner -> type -> stuff_values) + return (*(p -> inner -> type -> stuff_values)) (c, id, + p -> inner); + return ISC_R_SUCCESS; +} + +/* Set up a listener for the omapi protocol. The handle stored points to + a listener object, not a protocol object. */ + +isc_result_t omapi_protocol_listen (omapi_object_t *h, + int port, + int max) +{ + isc_result_t status; + omapi_protocol_listener_object_t *obj; + + obj = (omapi_protocol_listener_object_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + obj -> refcnt = 1; + obj -> type = omapi_type_protocol_listener; + + status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, + "omapi_protocol_listen"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_listen"); + return status; + } + status = omapi_object_reference (&obj -> inner, h, + "omapi_protocol_listen"); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_listen"); + return status; + } + + status = omapi_listen ((omapi_object_t *)obj, port, max); + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_listen"); + return status; +} + +/* Signal handler for protocol listener - if we get a connect signal, + create a new protocol connection, otherwise pass the signal down. */ + +isc_result_t omapi_protocol_listener_signal (omapi_object_t *o, + char *name, va_list ap) +{ + isc_result_t status; + omapi_object_t *c; + omapi_protocol_object_t *obj; + omapi_protocol_listener_object_t *p; + + if (!o || o -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + p = (omapi_protocol_listener_object_t *)o; + + /* Not a signal we recognize? */ + if (strcmp (name, "connect")) { + if (p -> inner && p -> inner -> type -> signal_handler) + return (*(p -> inner -> type -> signal_handler)) + (p -> inner, name, ap); + return ISC_R_NOTFOUND; + } + + c = va_arg (ap, omapi_object_t *); + if (!c || c -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + obj = (omapi_protocol_object_t *)malloc (sizeof *obj); + if (!obj) + return ISC_R_NOMEMORY; + memset (obj, 0, sizeof *obj); + obj -> refcnt = 1; + obj -> type = omapi_type_protocol; + + status = omapi_object_reference (&obj -> outer, c, + "omapi_protocol_accept"); + if (status != ISC_R_SUCCESS) { + lose: + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_accept"); + omapi_disconnect (c, 1); + return status; + } + + status = omapi_object_reference (&c -> inner, (omapi_object_t *)obj, + "omapi_protocol_accept"); + if (status != ISC_R_SUCCESS) + goto lose; + + /* Send the introductory message. */ + status = omapi_protocol_send_intro ((omapi_object_t *)obj, + OMAPI_PROTOCOL_VERSION, + sizeof (omapi_protocol_header_t)); + if (status != ISC_R_SUCCESS) + goto lose; + + omapi_object_dereference ((omapi_object_t **)&obj, + "omapi_protocol_accept"); + return status; +} + +isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h, char *name) +{ + if (h -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + return ISC_R_SUCCESS; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *p) +{ + int i; + + if (p -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + + if (p -> inner && p -> inner -> type -> stuff_values) + return (*(p -> inner -> type -> stuff_values)) (c, id, + p -> inner); + return ISC_R_SUCCESS; +} + diff --git a/omapip/result.c b/omapip/result.c new file mode 100644 index 00000000..8417b2cf --- /dev/null +++ b/omapip/result.c @@ -0,0 +1,76 @@ +/* result.c + + Cheap knock-off of libisc result table code. This is just a place-holder + until the actual libisc merge. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +static char *text[ISC_R_NRESULTS] = { + "success", /* 0 */ + "out of memory", /* 1 */ + "timed out", /* 2 */ + "no available threads", /* 3 */ + "address not available", /* 4 */ + "address in use", /* 5 */ + "permission denied", /* 6 */ + "no pending connections", /* 7 */ + "network unreachable", /* 8 */ + "host unreachable", /* 9 */ + "network down", /* 10 */ + "host down", /* 11 */ + "connection refused", /* 12 */ + "not enough free resources", /* 13 */ + "end of file", /* 14 */ + "socket already bound", /* 15 */ + "task is done", /* 16 */ + "lock busy", /* 17 */ + "already exists", /* 18 */ + "ran out of space", /* 19 */ + "operation canceled", /* 20 */ + "sending events is not allowed", /* 21 */ + "shutting down", /* 22 */ + "not found", /* 23 */ + "unexpected end of input", /* 24 */ + "failure", /* 25 */ + "I/O error", /* 26 */ + "not implemented", /* 27 */ + "unbalanced parentheses", /* 28 */ + "no more", /* 29 */ + "invalid file", /* 30 */ + "bad base64 encoding", /* 31 */ + "unexpected token", /* 32 */ + "quota reached", /* 33 */ + "unexpected error", /* 34 */ + "already running", /* 35 */ + "host unknown", /* 36 */ + "protocol version mismatch", /* 37 */ + "protocol error", /* 38 */ + "invalid argument", /* 39 */ + "not connected", /* 40 */ + "data not yet available", /* 41 */ +}; + +char *isc_result_totext (isc_result_t result) +{ + if (result >= ISC_R_SUCCESS && result < ISC_R_NRESULTS) + return text [result]; + return "unknown error."; +} diff --git a/omapip/support.c b/omapip/support.c new file mode 100644 index 00000000..1e8decf1 --- /dev/null +++ b/omapip/support.c @@ -0,0 +1,380 @@ +/* support.c + + Subroutines providing general support for objects. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +omapi_object_type_t *omapi_type_connection; +omapi_object_type_t *omapi_type_listener; +omapi_object_type_t *omapi_type_io_object; +omapi_object_type_t *omapi_type_datagram; +omapi_object_type_t *omapi_type_generic; +omapi_object_type_t *omapi_type_protocol; +omapi_object_type_t *omapi_type_protocol_listener; +omapi_object_type_t *omapi_type_waiter; +omapi_object_type_t *omapi_type_remote; +omapi_object_type_t *omapi_type_message; + +omapi_object_type_t *omapi_object_types; +int omapi_object_type_count; +static int ot_max; + +isc_result_t omapi_init (void) +{ + isc_result_t status; + + /* Register all the standard object types... */ + status = omapi_object_type_register (&omapi_type_connection, + "connection", + omapi_connection_set_value, + omapi_connection_get_value, + omapi_connection_destroy, + omapi_connection_signal_handler, + omapi_connection_stuff_values); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_listener, + "listener", + omapi_listener_set_value, + omapi_listener_get_value, + omapi_listener_destroy, + omapi_listener_signal_handler, + omapi_listener_stuff_values); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_io_object, + "io", + omapi_io_set_value, + omapi_io_get_value, + omapi_io_destroy, + omapi_io_signal_handler, + omapi_io_stuff_values); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_generic, + "generic", + omapi_generic_set_value, + omapi_generic_get_value, + omapi_generic_destroy, + omapi_generic_signal_handler, + omapi_generic_stuff_values); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_protocol, + "protocol", + omapi_protocol_set_value, + omapi_protocol_get_value, + omapi_protocol_destroy, + omapi_protocol_signal_handler, + omapi_protocol_stuff_values); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_protocol_listener, + "protocol-listener", + omapi_protocol_listener_set_value, + omapi_protocol_listener_get_value, + omapi_protocol_listener_destroy, + omapi_protocol_listener_signal, + omapi_protocol_listener_stuff); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_message, + "message", + omapi_message_set_value, + omapi_message_get_value, + omapi_message_destroy, + omapi_message_signal_handler, + omapi_message_stuff_values); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_waiter, + "waiter", + 0, + 0, + 0, + omapi_waiter_signal_handler, 0); + if (status != ISC_R_SUCCESS) + return status; + + /* This seems silly, but leave it. */ + return ISC_R_SUCCESS; +} + +isc_result_t omapi_object_type_register (omapi_object_type_t **type, + char *name, + isc_result_t (*set_value) + (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *), + isc_result_t (*get_value) + (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **), + isc_result_t (*destroy) + (omapi_object_t *, char *), + isc_result_t (*signal_handler) + (omapi_object_t *, + char *, va_list), + isc_result_t (*stuff_values) + (omapi_object_t *, + omapi_object_t *, + omapi_object_t *)) +{ + omapi_object_type_t *t; + + if (!omapi_object_types) { + ot_max = 10; + omapi_object_types = malloc (ot_max * + sizeof *omapi_object_types); + if (!omapi_object_types) + return ISC_R_NOMEMORY; + memset (omapi_object_types, 0, (ot_max * + sizeof *omapi_object_types)); + } else if (omapi_object_type_count == ot_max) { + t = malloc (2 *ot_max * sizeof *t); + if (!t) + return ISC_R_NOMEMORY; + memcpy (t, omapi_object_types, ot_max *sizeof *t); + memset (t + ot_max, 0, ot_max * sizeof *t); + free (omapi_object_types); + omapi_object_types = t; + } + omapi_object_types [omapi_object_type_count].name = name; + omapi_object_types [omapi_object_type_count].set_value = set_value; + omapi_object_types [omapi_object_type_count].get_value = get_value; + omapi_object_types [omapi_object_type_count].destroy = destroy; + omapi_object_types [omapi_object_type_count].signal_handler = + signal_handler; + omapi_object_types [omapi_object_type_count].stuff_values = + stuff_values; + if (type) + *type = &omapi_object_types [omapi_object_type_count]; + omapi_object_type_count++; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_signal (omapi_object_t *handle, char *name, ...) +{ + va_list ap; + omapi_object_t *outer; + isc_result_t status; + + va_start (ap, name); + for (outer = handle; outer -> outer; outer = outer -> outer) + ; + if (outer -> type -> signal_handler) + status = (*(outer -> type -> signal_handler)) (outer, + name, ap); + else + status = ISC_R_NOTFOUND; + va_end (ap); + return status; +} + +isc_result_t omapi_signal_in (omapi_object_t *handle, char *name, ...) +{ + va_list ap; + omapi_object_t *outer; + isc_result_t status; + + if (!handle) + return ISC_R_NOTFOUND; + va_start (ap, name); + + if (handle -> type -> signal_handler) + status = (*(handle -> type -> signal_handler)) (handle, + name, ap); + else + status = ISC_R_NOTFOUND; + va_end (ap); + return status; +} + +isc_result_t omapi_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + omapi_object_t *outer; + + for (outer = h; outer -> outer; outer = outer -> outer) + ; + if (outer -> type -> set_value) + return (*(outer -> type -> set_value)) (outer, + id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + omapi_object_t *outer; + + for (outer = h; outer -> outer; outer = outer -> outer) + ; + if (outer -> type -> get_value) + return (*(outer -> type -> get_value)) (outer, + id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *o) +{ + omapi_object_t *outer; + + for (outer = o; outer -> outer; outer = outer -> outer) + ; + if (outer -> type -> stuff_values) + return (*(outer -> type -> stuff_values)) (c, id, outer); + return ISC_R_NOTFOUND; +} + +int omapi_data_string_cmp (omapi_data_string_t *s1, omapi_data_string_t *s2) +{ + int len; + int rv; + + if (s1 -> len > s2 -> len) + len = s2 -> len; + else + len = s1 -> len; + rv = memcmp (s1 -> value, s2 -> value, len); + if (rv) + return rv; + if (s1 -> len > s2 -> len) + return 1; + else if (s1 -> len < s2 -> len) + return -1; + return 0; +} + +int omapi_ds_strcmp (omapi_data_string_t *s1, char *s2) +{ + int len, slen; + int rv; + + slen = strlen (s2); + if (slen > s1 -> len) + len = s1 -> len; + else + len = slen; + rv = memcmp (s1 -> value, s2, len); + if (rv) + return rv; + if (s1 -> len > slen) + return 1; + else if (s1 -> len < slen) + return -1; + return 0; +} + +isc_result_t omapi_make_value (omapi_value_t **vp, omapi_data_string_t *name, + omapi_typed_data_t *value, char *caller) +{ + isc_result_t status; + + status = omapi_value_new (vp, caller); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference (&(*vp) -> name, name, caller); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, caller); + return status; + } + if (value) { + status = omapi_typed_data_reference (&(*vp) -> value, + value, caller); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, caller); + return status; + } + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_make_const_value (omapi_value_t **vp, + omapi_data_string_t *name, + u_int8_t *value, int len, char *caller) +{ + isc_result_t status; + + status = omapi_value_new (vp, caller); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference (&(*vp) -> name, name, caller); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, caller); + return status; + } + if (value) { + status = omapi_typed_data_new (&(*vp) -> value, + omapi_datatype_data, len); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, caller); + return status; + } + memcpy ((*vp) -> value -> u.buffer.value, value, len); + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_make_int_value (omapi_value_t **vp, + omapi_data_string_t *name, + int value, char *caller) +{ + isc_result_t status; + + status = omapi_value_new (vp, caller); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference (&(*vp) -> name, name, caller); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, caller); + return status; + } + if (value) { + status = omapi_typed_data_new (&(*vp) -> value, + omapi_datatype_int); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, caller); + return status; + } + (*vp) -> value -> u.integer = value; + } + return ISC_R_SUCCESS; +} + diff --git a/omapip/test.c b/omapip/test.c new file mode 100644 index 00000000..4c0e164f --- /dev/null +++ b/omapip/test.c @@ -0,0 +1,80 @@ +/* test.c + + Test code for omapip... */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ + +#include <omapip/omapip.h> + +int main (int argc, char **argv) +{ + omapi_object_t listener = (omapi_object_t)0; + omapi_object_t connection = (omapi_object_t)0; + isc_result_t status; + + omapi_init (); + + if (argc > 1 && !strcmp (argv [1], "listen")) { + if (argc < 3) { + fprintf (stderr, "Usage: test listen port\n"); + exit (1); + } + status = omapi_generic_new (&listener, "main"); + if (status != ISC_R_SUCCESS) { + fprintf (stderr, "omapi_generic_new: %s\n", + isc_result_totext (status)); + exit (1); + } + status = omapi_protocol_listen (listener, + atoi (argv [2]), 1); + if (status != ISC_R_SUCCESS) { + fprintf (stderr, "omapi_listen: %s\n", + isc_result_totext (status)); + exit (1); + } + omapi_dispatch (0); + } else if (argc > 1 && !strcmp (argv [1], "connect")) { + if (argc < 4) { + fprintf (stderr, "Usage: test listen address port\n"); + exit (1); + } + status = omapi_generic_new (&connection, "main"); + if (status != ISC_R_SUCCESS) { + fprintf (stderr, "omapi_generic_new: %s\n", + isc_result_totext (status)); + exit (1); + } + status = omapi_protocol_connect (connection, + argv [2], atoi (argv [3]), 0); + fprintf (stderr, "connect: %s\n", isc_result_totext (status)); + if (status != ISC_R_SUCCESS) + exit (1); + status = omapi_wait_for_completion (connection, 0); + fprintf (stderr, "completion: %s\n", + isc_result_totext (status)); + if (status != ISC_R_SUCCESS) + exit (1); + /* ... */ + } else { + fprintf (stderr, "Usage: test [listen | connect] ...\n"); + exit (1); + } + + return 0; +} |