aboutsummaryrefslogtreecommitdiff
path: root/omapip/generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'omapip/generic.c')
-rw-r--r--omapip/generic.c305
1 files changed, 305 insertions, 0 deletions
diff --git a/omapip/generic.c b/omapip/generic.c
new file mode 100644
index 0000000..26e9361
--- /dev/null
+++ b/omapip/generic.c
@@ -0,0 +1,305 @@
+/* generic.c
+
+ Subroutines that support the generic object. */
+
+/*
+ * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ * This software has been written for Internet Systems Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about Internet Systems Consortium, see
+ * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#include "dhcpd.h"
+
+#include <omapip/omapip_p.h>
+
+OMAPI_OBJECT_ALLOC (omapi_generic,
+ omapi_generic_object_t, omapi_type_generic)
+
+isc_result_t omapi_generic_new (omapi_object_t **gen,
+ const char *file, int line)
+{
+ /* Backwards compatibility. */
+ return omapi_generic_allocate ((omapi_generic_object_t **)gen,
+ file, line);
+}
+
+isc_result_t omapi_generic_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ omapi_generic_object_t *g;
+ omapi_value_t *new;
+ omapi_value_t **va;
+ u_int8_t *ca;
+ int vm_new;
+ int i, vfree = -1;
+ isc_result_t status;
+
+ if (h -> type != omapi_type_generic)
+ return DHCP_R_INVALIDARG;
+ g = (omapi_generic_object_t *)h;
+
+ /* See if there's already a value with this name attached to
+ the generic object, and if so, replace the current value
+ with the new one. */
+ for (i = 0; i < g -> nvalues; i++) {
+ if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
+ /* There's an inconsistency here: the standard
+ behaviour of a set_values method when
+ passed a matching name and a null value is
+ to delete the value associated with that
+ name (where possible). In the generic
+ object, we remember the name/null pair,
+ because generic objects are generally used
+ to pass messages around, and this is the
+ way that remote entities delete values from
+ local objects. If the get_value method of
+ a generic object is called for a name that
+ maps to a name/null pair, ISC_R_NOTFOUND is
+ returned. */
+ new = (omapi_value_t *)0;
+ status = (omapi_value_new (&new, MDL));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ omapi_data_string_reference (&new -> name, name, MDL);
+ if (value)
+ omapi_typed_data_reference (&new -> value,
+ value, MDL);
+
+ omapi_value_dereference (&(g -> values [i]), MDL);
+ status = (omapi_value_reference
+ (&(g -> values [i]), new, MDL));
+ omapi_value_dereference (&new, MDL);
+ g -> changed [i] = 1;
+ return status;
+ }
+ /* Notice a free slot if we pass one. */
+ else if (vfree == -1 && !g -> values [i])
+ vfree = i;
+ }
+
+ /* If the name isn't already attached to this object, see if an
+ inner object has it. */
+ if (h -> inner && h -> inner -> type -> set_value) {
+ status = ((*(h -> inner -> type -> set_value))
+ (h -> inner, id, name, value));
+ if (status != ISC_R_NOTFOUND)
+ return status;
+ }
+
+ /* Okay, so it's a value that no inner object knows about, and
+ (implicitly, since the outer object set_value method would
+ have called this object's set_value method) it's an object that
+ no outer object knows about, it's this object's responsibility
+ to remember it - that's what generic objects do. */
+
+ /* Arrange for there to be space for the pointer to the new
+ name/value pair if necessary: */
+ if (vfree == -1) {
+ vfree = g -> nvalues;
+ if (vfree == g -> va_max) {
+ if (g -> va_max)
+ vm_new = 2 * g -> va_max;
+ else
+ vm_new = 10;
+ va = dmalloc (vm_new * sizeof *va, MDL);
+ if (!va)
+ return ISC_R_NOMEMORY;
+ ca = dmalloc (vm_new * sizeof *ca, MDL);
+ if (!ca) {
+ dfree (va, MDL);
+ return ISC_R_NOMEMORY;
+ }
+ if (g -> va_max) {
+ memcpy (va, g -> values,
+ g -> va_max * sizeof *va);
+ memcpy (ca, g -> changed,
+ g -> va_max * sizeof *ca);
+ }
+ memset (va + g -> va_max, 0,
+ (vm_new - g -> va_max) * sizeof *va);
+ memset (ca + g -> va_max, 0,
+ (vm_new - g -> va_max) * sizeof *ca);
+ if (g -> values)
+ dfree (g -> values, MDL);
+ if (g -> changed)
+ dfree (g -> changed, MDL);
+ g -> values = va;
+ g -> changed = ca;
+ g -> va_max = vm_new;
+ }
+ }
+ status = omapi_value_new (&g -> values [vfree], MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ omapi_data_string_reference (&g -> values [vfree] -> name,
+ name, MDL);
+ if (value)
+ omapi_typed_data_reference
+ (&g -> values [vfree] -> value, value, MDL);
+ g -> changed [vfree] = 1;
+ if (vfree == g -> nvalues)
+ g -> nvalues++;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_generic_get_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ int i;
+ omapi_generic_object_t *g;
+
+ if (h -> type != omapi_type_generic)
+ return DHCP_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 (!g -> values[i])
+ continue;
+ if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
+ /* If this is a name/null value pair, this is the
+ same as if there were no value that matched
+ the specified name, so return ISC_R_NOTFOUND. */
+ if (!g -> values [i] -> value)
+ return ISC_R_NOTFOUND;
+ /* Otherwise, return the name/value pair. */
+ return omapi_value_reference (value,
+ g -> values [i], MDL);
+ }
+ }
+
+ if (h -> inner && h -> inner -> type -> get_value)
+ return (*(h -> inner -> type -> get_value))
+ (h -> inner, id, name, value);
+ return ISC_R_NOTFOUND;
+}
+
+isc_result_t omapi_generic_destroy (omapi_object_t *h,
+ const char *file, int line)
+{
+ omapi_generic_object_t *g;
+ int i;
+
+ if (h -> type != omapi_type_generic)
+ return ISC_R_UNEXPECTED;
+ g = (omapi_generic_object_t *)h;
+
+ if (g -> values) {
+ for (i = 0; i < g -> nvalues; i++) {
+ if (g -> values [i])
+ omapi_value_dereference (&g -> values [i],
+ file, line);
+ }
+ dfree (g -> values, file, line);
+ dfree (g -> changed, file, line);
+ g -> values = (omapi_value_t **)0;
+ g -> changed = (u_int8_t *)0;
+ g -> va_max = 0;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t omapi_generic_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != omapi_type_generic)
+ return DHCP_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 DHCP_R_INVALIDARG;
+ src = (omapi_generic_object_t *)g;
+
+ for (i = 0; i < src -> nvalues; i++) {
+ if (src -> values [i] && src -> values [i] -> name -> len &&
+ src -> changed [i]) {
+ status = (omapi_connection_put_uint16
+ (c, src -> values [i] -> name -> len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_copyin
+ (c, src -> values [i] -> name -> value,
+ src -> values [i] -> name -> len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = (omapi_connection_write_typed_data
+ (c, src -> values [i] -> value));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ }
+
+ if (g -> inner && g -> inner -> type -> stuff_values)
+ return (*(g -> inner -> type -> stuff_values)) (c, id,
+ g -> inner);
+ return ISC_R_SUCCESS;
+}
+
+/* Clear the changed flags on the object. This has the effect that if
+ generic_stuff is called, any attributes that still have a cleared changed
+ flag aren't sent to the peer. This also deletes any values that are
+ null, presuming that these have now been properly handled. */
+
+isc_result_t omapi_generic_clear_flags (omapi_object_t *o)
+{
+ int i;
+ omapi_generic_object_t *g;
+
+ if (o -> type != omapi_type_generic)
+ return DHCP_R_INVALIDARG;
+ g = (omapi_generic_object_t *)o;
+
+ for (i = 0; i < g -> nvalues; i++) {
+ g -> changed [i] = 0;
+ if (g -> values [i] &&
+ !g -> values [i] -> value)
+ omapi_value_dereference (&g -> values [i], MDL);
+ }
+ return ISC_R_SUCCESS;
+}