mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-22 18:07:25 +00:00
284 lines
9.5 KiB
C
284 lines
9.5 KiB
C
/* 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);
|
|
}
|
|
|
|
/* For looking up objects based on handles that have been sent on the wire. */
|
|
isc_result_t omapi_handle_td_lookup (omapi_object_t **obj,
|
|
omapi_typed_data_t *handle)
|
|
{
|
|
isc_result_t status;
|
|
omapi_handle_t h;
|
|
|
|
if (handle -> type == omapi_datatype_int)
|
|
h = handle -> u.integer;
|
|
else if (handle -> type == omapi_datatype_data &&
|
|
handle -> u.buffer.len == sizeof h) {
|
|
memcpy (&h, handle -> u.buffer.value, sizeof h);
|
|
h = ntohl (h);
|
|
} else
|
|
return ISC_R_INVALIDARG;
|
|
return omapi_handle_lookup (obj, h);
|
|
}
|