/* generic.c Subroutines that support the generic object. */ /* * Copyright (c) 1999-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about the Internet Software Consortium, see * ``http://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include OMAPI_OBJECT_ALLOC (omapi_generic, omapi_generic_object_t, omapi_type_generic) isc_result_t omapi_generic_new (omapi_object_t **gen, const char *file, int line) { /* Backwards compatibility. */ return omapi_generic_allocate ((omapi_generic_object_t **)gen, file, line); } isc_result_t omapi_generic_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { omapi_generic_object_t *g; omapi_value_t *new; omapi_value_t **va; u_int8_t *ca; int vm_new; int i, vfree = -1; isc_result_t status; if (h -> type != omapi_type_generic) return ISC_R_INVALIDARG; g = (omapi_generic_object_t *)h; /* See if there's already a value with this name attached to the generic object, and if so, replace the current value with the new one. */ for (i = 0; i < g -> nvalues; i++) { if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { /* There's an inconsistency here: the standard behaviour of a set_values method when passed a matching name and a null value is to delete the value associated with that name (where possible). In the generic object, we remember the name/null pair, because generic objects are generally used to pass messages around, and this is the way that remote entities delete values from local objects. If the get_value method of a generic object is called for a name that maps to a name/null pair, ISC_R_NOTFOUND is returned. */ new = (omapi_value_t *)0; status = (omapi_value_new (&new, MDL)); if (status != ISC_R_SUCCESS) return status; omapi_data_string_reference (&new -> name, name, MDL); if (value) omapi_typed_data_reference (&new -> value, value, MDL); omapi_value_dereference (&(g -> values [i]), MDL); status = (omapi_value_reference (&(g -> values [i]), new, MDL)); omapi_value_dereference (&new, MDL); g -> changed [i] = 1; return status; } /* Notice a free slot if we pass one. */ else if (vfree == -1 && !g -> values [i]) vfree = i; } /* If the name isn't already attached to this object, see if an inner object has it. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status != ISC_R_NOTFOUND) return status; } /* Okay, so it's a value that no inner object knows about, and (implicitly, since the outer object set_value method would have called this object's set_value method) it's an object that no outer object knows about, it's this object's responsibility to remember it - that's what generic objects do. */ /* Arrange for there to be space for the pointer to the new name/value pair if necessary: */ if (vfree == -1) { vfree = g -> nvalues; if (vfree == g -> va_max) { if (g -> va_max) vm_new = 2 * g -> va_max; else vm_new = 10; va = dmalloc (vm_new * sizeof *va, MDL); if (!va) return ISC_R_NOMEMORY; ca = dmalloc (vm_new * sizeof *ca, MDL); if (!ca) { dfree (va, MDL); return ISC_R_NOMEMORY; } if (g -> va_max) { memcpy (va, g -> values, g -> va_max * sizeof *va); memcpy (ca, g -> changed, g -> va_max * sizeof *ca); } memset (va + g -> va_max, 0, (vm_new - g -> va_max) * sizeof *va); memset (ca + g -> va_max, 0, (vm_new - g -> va_max) * sizeof *ca); if (g -> values) dfree (g -> values, MDL); if (g -> changed) dfree (g -> changed, MDL); g -> values = va; g -> changed = ca; g -> va_max = vm_new; } } status = omapi_value_new (&g -> values [vfree], MDL); if (status != ISC_R_SUCCESS) return status; omapi_data_string_reference (&g -> values [vfree] -> name, name, MDL); if (value) omapi_typed_data_reference (&g -> values [vfree] -> value, value, MDL); g -> changed [vfree] = 1; if (vfree == g -> nvalues) g -> nvalues++; return ISC_R_SUCCESS; } isc_result_t omapi_generic_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { int i; omapi_generic_object_t *g; if (h -> type != omapi_type_generic) return ISC_R_INVALIDARG; g = (omapi_generic_object_t *)h; /* Look up the specified name in our list of objects. */ for (i = 0; i < g -> nvalues; i++) { if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { /* If this is a name/null value pair, this is the same as if there were no value that matched the specified name, so return ISC_R_NOTFOUND. */ if (!g -> values [i] -> value) return ISC_R_NOTFOUND; /* Otherwise, return the name/value pair. */ return omapi_value_reference (value, g -> values [i], MDL); } } if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_generic_destroy (omapi_object_t *h, const char *file, int line) { omapi_generic_object_t *g; int i; if (h -> type != omapi_type_generic) return ISC_R_UNEXPECTED; g = (omapi_generic_object_t *)h; if (g -> values) { for (i = 0; i < g -> nvalues; i++) { if (g -> values [i]) omapi_value_dereference (&g -> values [i], file, line); } dfree (g -> values, file, line); dfree (g -> changed, file, line); g -> values = (omapi_value_t **)0; g -> changed = (u_int8_t *)0; g -> va_max = 0; } return ISC_R_SUCCESS; } isc_result_t omapi_generic_signal_handler (omapi_object_t *h, const char *name, va_list ap) { if (h -> type != omapi_type_generic) return ISC_R_INVALIDARG; if (h -> inner && h -> inner -> type -> signal_handler) return (*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap); return ISC_R_NOTFOUND; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t omapi_generic_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *g) { omapi_generic_object_t *src; int i; isc_result_t status; if (g -> type != omapi_type_generic) return ISC_R_INVALIDARG; src = (omapi_generic_object_t *)g; for (i = 0; i < src -> nvalues; i++) { if (src -> values [i] && src -> values [i] -> name -> len && src -> changed [i]) { status = (omapi_connection_put_uint16 (c, src -> values [i] -> name -> len)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_copyin (c, src -> values [i] -> name -> value, src -> values [i] -> name -> len)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_write_typed_data (c, src -> values [i] -> value)); if (status != ISC_R_SUCCESS) return status; } } if (g -> inner && g -> inner -> type -> stuff_values) return (*(g -> inner -> type -> stuff_values)) (c, id, g -> inner); return ISC_R_SUCCESS; } /* Clear the changed flags on the object. This has the effect that if generic_stuff is called, any attributes that still have a cleared changed flag aren't sent to the peer. This also deletes any values that are null, presuming that these have now been properly handled. */ isc_result_t omapi_generic_clear_flags (omapi_object_t *o) { int i; omapi_generic_object_t *g; if (o -> type != omapi_type_generic) return ISC_R_INVALIDARG; g = (omapi_generic_object_t *)o; for (i = 0; i < g -> nvalues; i++) { g -> changed [i] = 0; if (g -> values [i] && !g -> values [i] -> value) omapi_value_dereference (&g -> values [i], MDL); } return ISC_R_SUCCESS; }