Annotation of embedaddon/dhcp/omapip/handle.c, revision 1.1.1.1
1.1 misho 1: /* handle.c
2:
3: Functions for maintaining handles on objects. */
4:
5: /*
1.1.1.1 ! misho 6: * Copyright (c) 2009-2010,2012 by Internet Systems Consortium, Inc. ("ISC")
1.1 misho 7: * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8: * Copyright (c) 1999-2003 by Internet Software Consortium
9: *
10: * Permission to use, copy, modify, and distribute this software for any
11: * purpose with or without fee is hereby granted, provided that the above
12: * copyright notice and this permission notice appear in all copies.
13: *
14: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21: *
22: * Internet Systems Consortium, Inc.
23: * 950 Charter Street
24: * Redwood City, CA 94063
25: * <info@isc.org>
26: * https://www.isc.org/
27: *
28: * This software has been written for Internet Systems Consortium
29: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30: * To learn more about Internet Systems Consortium, see
31: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
32: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33: * ``http://www.nominum.com''.
34: */
35:
36: #include "dhcpd.h"
37:
38: #include <omapip/omapip_p.h>
39:
40: /* The handle table is a hierarchical tree designed for quick mapping
41: of handle identifiers to objects. Objects contain their own handle
42: identifiers if they have them, so the reverse mapping is also
43: quick. The hierarchy is made up of table objects, each of which
44: has 120 entries, a flag indicating whether the table is a leaf
45: table or an indirect table, the handle of the first object covered
46: by the table and the first object after that that's *not* covered
47: by the table, a count of how many objects of either type are
48: currently stored in the table, and an array of 120 entries pointing
49: either to objects or tables.
50:
51: When we go to add an object to the table, we look to see if the
52: next object handle to be assigned is covered by the outermost
53: table. If it is, we find the place within that table where the
54: next handle should go, and if necessary create additional nodes in
55: the tree to contain the new handle. The pointer to the object is
56: then stored in the correct position.
57:
58: Theoretically, we could have some code here to free up handle
59: tables as they go out of use, but by and large handle tables won't
60: go out of use, so this is being skipped for now. It shouldn't be
61: too hard to implement in the future if there's a different
62: application. */
63:
64: omapi_handle_table_t *omapi_handle_table;
65: omapi_handle_t omapi_next_handle = 1; /* Next handle to be assigned. */
66:
67: #define FIND_HAND 0
68: #define CLEAR_HAND 1
69:
70: static isc_result_t omapi_handle_lookup_in (omapi_object_t **,
71: omapi_handle_t,
72: omapi_handle_table_t *,
73: int);
74: static isc_result_t omapi_object_handle_in_table (omapi_handle_t,
75: omapi_handle_table_t *,
76: omapi_object_t *);
77: static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **);
78:
79: isc_result_t omapi_object_handle (omapi_handle_t *h, omapi_object_t *o)
80: {
81: isc_result_t status;
82:
83: if (o -> handle) {
84: *h = o -> handle;
85: return ISC_R_SUCCESS;
86: }
87:
88: if (!omapi_handle_table) {
89: omapi_handle_table = dmalloc (sizeof *omapi_handle_table, MDL);
90: if (!omapi_handle_table)
91: return ISC_R_NOMEMORY;
92: memset (omapi_handle_table, 0, sizeof *omapi_handle_table);
93: omapi_handle_table -> first = 0;
94: omapi_handle_table -> limit = OMAPI_HANDLE_TABLE_SIZE;
95: omapi_handle_table -> leafp = 1;
96: }
97:
98: /* If this handle doesn't fit in the outer table, we need to
99: make a new outer table. This is a while loop in case for
100: some reason we decide to do disjoint handle allocation,
101: where the next level of indirection still isn't big enough
102: to enclose the next handle ID. */
103:
104: while (omapi_next_handle >= omapi_handle_table -> limit) {
105: omapi_handle_table_t *new;
106:
107: new = dmalloc (sizeof *new, MDL);
108: if (!new)
109: return ISC_R_NOMEMORY;
110: memset (new, 0, sizeof *new);
111: new -> first = 0;
112: new -> limit = (omapi_handle_table -> limit *
113: OMAPI_HANDLE_TABLE_SIZE);
114: new -> leafp = 0;
115: new -> children [0].table = omapi_handle_table;
116: omapi_handle_table = new;
117: }
118:
119: /* Try to cram this handle into the existing table. */
120: status = omapi_object_handle_in_table (omapi_next_handle,
121: omapi_handle_table, o);
122: /* If it worked, return the next handle and increment it. */
123: if (status == ISC_R_SUCCESS) {
124: *h = omapi_next_handle;
125: omapi_next_handle++;
126: return ISC_R_SUCCESS;
127: }
128: if (status != ISC_R_NOSPACE)
129: return status;
130:
131: status = omapi_handle_table_enclose (&omapi_handle_table);
132: if (status != ISC_R_SUCCESS)
133: return status;
134:
135: status = omapi_object_handle_in_table (omapi_next_handle,
136: omapi_handle_table, o);
137: if (status != ISC_R_SUCCESS)
138: return status;
139: *h = omapi_next_handle;
140: omapi_next_handle++;
141:
142: return ISC_R_SUCCESS;
143: }
144:
145: static isc_result_t omapi_object_handle_in_table (omapi_handle_t h,
146: omapi_handle_table_t *table,
147: omapi_object_t *o)
148: {
149: omapi_handle_table_t *inner;
150: omapi_handle_t scale, index;
151: isc_result_t status;
152:
153: if (table -> first > h || table -> limit <= h)
154: return ISC_R_NOSPACE;
155:
156: /* If this is a leaf table, just stash the object in the
157: appropriate place. */
158: if (table -> leafp) {
159: status = (omapi_object_reference
160: (&table -> children [h - table -> first].object,
161: o, MDL));
162: if (status != ISC_R_SUCCESS)
163: return status;
164: o -> handle = h;
165: return ISC_R_SUCCESS;
166: }
167:
168: /* Scale is the number of handles represented by each child of this
169: table. For a leaf table, scale would be 1. For a first level
170: of indirection, 120. For a second, 120 * 120. Et cetera. */
171: scale = (table -> limit - table -> first) / OMAPI_HANDLE_TABLE_SIZE;
172:
173: /* So the next most direct table from this one that contains the
174: handle must be the subtable of this table whose index into this
175: table's array of children is the handle divided by the scale. */
176: index = (h - table -> first) / scale;
177: inner = table -> children [index].table;
178:
179: /* If there is no more direct table than this one in the slot
180: we came up with, make one. */
181: if (!inner) {
182: inner = dmalloc (sizeof *inner, MDL);
183: if (!inner)
184: return ISC_R_NOMEMORY;
185: memset (inner, 0, sizeof *inner);
186: inner -> first = index * scale + table -> first;
187: inner -> limit = inner -> first + scale;
188: if (scale == OMAPI_HANDLE_TABLE_SIZE)
189: inner -> leafp = 1;
190: table -> children [index].table = inner;
191: }
192:
193: status = omapi_object_handle_in_table (h, inner, o);
194: if (status == ISC_R_NOSPACE) {
195: status = (omapi_handle_table_enclose
196: (&table -> children [index].table));
197: if (status != ISC_R_SUCCESS)
198: return status;
199:
200: return omapi_object_handle_in_table
201: (h, table -> children [index].table, o);
202: }
203: return status;
204: }
205:
206: static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **table)
207: {
208: omapi_handle_table_t *inner = *table;
209: omapi_handle_table_t *new;
210: int index, base, scale;
211:
212: /* The scale of the table we're enclosing is going to be the
213: difference between its "first" and "limit" members. So the
214: scale of the table enclosing it is going to be that multiplied
215: by the table size. */
216: scale = (inner -> first - inner -> limit) * OMAPI_HANDLE_TABLE_SIZE;
217:
218: /* The range that the enclosing table covers is going to be
219: the result of subtracting the remainder of dividing the
220: enclosed table's first entry number by the enclosing
221: table's scale. If handle IDs are being allocated
222: sequentially, the enclosing table's "first" value will be
223: the same as the enclosed table's "first" value. */
224: base = inner -> first - inner -> first % scale;
225:
226: /* The index into the enclosing table at which the enclosed table
227: will be stored is going to be the difference between the "first"
228: value of the enclosing table and the enclosed table - zero, if
229: we are allocating sequentially. */
230: index = (base - inner -> first) / OMAPI_HANDLE_TABLE_SIZE;
231:
232: new = dmalloc (sizeof *new, MDL);
233: if (!new)
234: return ISC_R_NOMEMORY;
235: memset (new, 0, sizeof *new);
236: new -> first = base;
237: new -> limit = base + scale;
238: if (scale == OMAPI_HANDLE_TABLE_SIZE)
239: new -> leafp = 0;
240: new -> children [index].table = inner;
241: *table = new;
242: return ISC_R_SUCCESS;
243: }
244:
245: isc_result_t omapi_handle_lookup (omapi_object_t **o, omapi_handle_t h)
246: {
247: return(omapi_handle_lookup_in(o, h, omapi_handle_table, FIND_HAND));
248: }
249:
250: static isc_result_t omapi_handle_lookup_in (omapi_object_t **o,
251: omapi_handle_t h,
252: omapi_handle_table_t *table,
253: int op)
254: {
255: omapi_handle_t scale, index;
256:
257: if (!table || table->first > h || table->limit <= h)
258: return(ISC_R_NOTFOUND);
259:
260: /* If this is a leaf table, just grab the object. */
261: if (table->leafp) {
262: /* Not there? */
263: if (!table->children[h - table->first].object)
264: return(ISC_R_NOTFOUND);
265: if (op == CLEAR_HAND) {
266: table->children[h - table->first].object = NULL;
267: return(ISC_R_SUCCESS);
268: } else {
269: return(omapi_object_reference
270: (o, table->children[h - table->first].object,
271: MDL));
272: }
273: }
274:
275: /* Scale is the number of handles represented by each child of this
276: table. For a leaf table, scale would be 1. For a first level
277: of indirection, 120. For a second, 120 * 120. Et cetera. */
278: scale = (table->limit - table->first) / OMAPI_HANDLE_TABLE_SIZE;
279:
280: /* So the next most direct table from this one that contains the
281: handle must be the subtable of this table whose index into this
282: table's array of children is the handle divided by the scale. */
283: index = (h - table->first) / scale;
284:
285: return(omapi_handle_lookup_in(o, h, table->children[index].table, op));
286: }
287:
288: /* For looking up objects based on handles that have been sent on the wire. */
289: isc_result_t omapi_handle_td_lookup (omapi_object_t **obj,
290: omapi_typed_data_t *handle)
291: {
292: omapi_handle_t h;
293:
294: if (handle->type == omapi_datatype_int)
295: h = handle->u.integer;
296: else if (handle->type == omapi_datatype_data &&
297: handle->u.buffer.len == sizeof h) {
298: memcpy(&h, handle->u.buffer.value, sizeof h);
299: h = ntohl(h);
300: } else
301: return(ISC_R_INVALIDARG);
302: return(omapi_handle_lookup(obj, h));
303: }
304:
305: isc_result_t omapi_handle_clear(omapi_handle_t h)
306: {
307: return(omapi_handle_lookup_in(NULL, h, omapi_handle_table, CLEAR_HAND));
308: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>