/* * Copyright (C) 1996, 1997, 1998, 1999, 2000 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM 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. */ /* $Id: generic.c,v 1.11 2000/03/14 03:38:54 tale Exp $ */ /* Principal Author: Ted Lemon */ /* * Subroutines that support the generic object. */ #include /* NULL */ #include /* memset */ #include #include static isc_result_t generic_setvalue(omapi_object_t *h, omapi_string_t *name, omapi_data_t *value) { omapi_generic_t *g; omapi_value_t *new; omapi_value_t **va; int vm_new; unsigned int i; isc_result_t result; REQUIRE(h != NULL && h->type == omapi_type_generic); g = (omapi_generic_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_string_stringcmp(name, g->values[i]->name) == 0) { /* * 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 = NULL; result = omapi_value_create(&new); if (result != ISC_R_SUCCESS) return (result); omapi_string_reference(&new->name, name); if (value != NULL) omapi_data_reference(&new->value, value); omapi_value_dereference(&(g->values[i])); omapi_value_reference(&(g->values[i]), new); omapi_value_dereference(&new); return (ISC_R_SUCCESS); } } /* * If the name isn't already attached to this object, see if an * inner object has it. */ result = omapi_object_passsetvalue(h, name, value); if (result != ISC_R_NOTFOUND) return (result); /* * 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) { /* * Increase the maximum number of values by 10. * 10 is an arbitrary constant. */ vm_new = g->va_max + 10; va = isc_mem_get(omapi_mctx, vm_new * sizeof(*va)); if (va == NULL) return (ISC_R_NOMEMORY); if (g->va_max != 0) { memcpy(va, g->values, g->va_max * sizeof(*va)); isc_mem_put(omapi_mctx, g->values, g->va_max * sizeof(*va)); } memset(va + g->va_max, 0, (vm_new - g->va_max) * sizeof(*va)); g->values = va; g->va_max = vm_new; } result = omapi_value_create(&g->values[g->nvalues]); if (result != ISC_R_SUCCESS) return (result); omapi_string_reference(&g->values[g->nvalues]->name, name); if (value != NULL) omapi_data_reference(&g->values[g->nvalues]->value, value); g->nvalues++; return (ISC_R_SUCCESS); } static isc_result_t generic_getvalue(omapi_object_t *h, omapi_string_t *name, omapi_value_t **value) { unsigned int i; omapi_generic_t *g; REQUIRE(h != NULL && h->type == omapi_type_generic); g = (omapi_generic_t *)h; /* * Look up the specified name in our list of objects. */ for (i = 0; i < g->nvalues; i++) { if (omapi_string_stringcmp(name, g->values[i]->name) == 0) { /* * 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 == NULL) return (ISC_R_NOTFOUND); /* * Otherwise, return the name/value pair. */ omapi_value_reference(value, g->values[i]); return (ISC_R_SUCCESS); } } return (omapi_object_passgetvalue(h, name, value)); } static void generic_destroy(omapi_object_t *h) { omapi_generic_t *g; unsigned int i; REQUIRE(h != NULL && h->type == omapi_type_generic); g = (omapi_generic_t *)h; if (g->values != NULL) { for (i = 0; i < g->nvalues; i++) if (g->values[i] != NULL) omapi_value_dereference(&g->values[i]); isc_mem_put(omapi_mctx, g->values, g->va_max * sizeof(*g->values)); g->values = NULL; g->va_max = 0; } } static isc_result_t generic_signalhandler(omapi_object_t *h, const char *name, va_list ap) { REQUIRE(h != NULL && h->type == omapi_type_generic); /* * XXXDCL I suppose that ideally the status would be set in all * objects in the chain. */ if (strcmp(name, "status") == 0) { h->waitresult = va_arg(ap, isc_result_t); return (ISC_R_SUCCESS); } return (omapi_object_passsignal(h, name, ap)); } /* * Write all the published values associated with the object through the * specified connection. */ static isc_result_t generic_stuffvalues(omapi_object_t *connection, omapi_object_t *h) { omapi_generic_t *src; unsigned int i; isc_result_t result; REQUIRE(h != NULL && h->type == omapi_type_generic); src = (omapi_generic_t *)h; for (i = 0; i < src->nvalues; i++) { if (src->values[i] != NULL && src->values[i]->name->len != 0) { result = omapi_connection_putuint16(connection, src->values[i]->name->len); if (result != ISC_R_SUCCESS) return (result); result = omapi_connection_putmem(connection, src->values[i]->name->value, src->values[i]->name->len); if (result != ISC_R_SUCCESS) return (result); result = omapi_connection_putdata(connection, src->values[i]->value); if (result != ISC_R_SUCCESS) return (result); } } return (omapi_object_passstuffvalues(connection, h)); } isc_result_t generic_init(void) { return (omapi_object_register(&omapi_type_generic, "generic", generic_setvalue, generic_getvalue, generic_destroy, generic_signalhandler, generic_stuffvalues, NULL, NULL, NULL)); }