/* 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 isc_result_t omapi_generic_new (omapi_object_t **gen, const 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; g -> va_max = vm_new; } 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, const 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, 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) { 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; }