Merge from vendor branch BINUTILS:
[dragonfly.git] / contrib / dhcp-3.0 / omapip / generic.c
1 /* generic.c
2
3    Subroutines that support the generic object. */
4
5 /*
6  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1999-2003 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  *   Internet Systems Consortium, Inc.
22  *   950 Charter Street
23  *   Redwood City, CA 94063
24  *   <info@isc.org>
25  *   http://www.isc.org/
26  *
27  * This software has been written for Internet Systems Consortium
28  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29  * To learn more about Internet Systems Consortium, see
30  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
31  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32  * ``http://www.nominum.com''.
33  */
34
35 #include <omapip/omapip_p.h>
36
37 OMAPI_OBJECT_ALLOC (omapi_generic,
38                     omapi_generic_object_t, omapi_type_generic)
39
40 isc_result_t omapi_generic_new (omapi_object_t **gen,
41                                 const char *file, int line)
42 {
43         /* Backwards compatibility. */
44         return omapi_generic_allocate ((omapi_generic_object_t **)gen,
45                                        file, line);
46 }
47
48 isc_result_t omapi_generic_set_value (omapi_object_t *h,
49                                       omapi_object_t *id,
50                                       omapi_data_string_t *name,
51                                       omapi_typed_data_t *value)
52 {
53         omapi_generic_object_t *g;
54         omapi_value_t *new;
55         omapi_value_t **va;
56         u_int8_t *ca;
57         int vm_new;
58         int i, vfree = -1;
59         isc_result_t status;
60
61         if (h -> type != omapi_type_generic)
62                 return ISC_R_INVALIDARG;
63         g = (omapi_generic_object_t *)h;
64
65         /* See if there's already a value with this name attached to
66            the generic object, and if so, replace the current value
67            with the new one. */
68         for (i = 0; i < g -> nvalues; i++) {
69                 if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
70                         /* There's an inconsistency here: the standard
71                            behaviour of a set_values method when
72                            passed a matching name and a null value is
73                            to delete the value associated with that
74                            name (where possible).  In the generic
75                            object, we remember the name/null pair,
76                            because generic objects are generally used
77                            to pass messages around, and this is the
78                            way that remote entities delete values from
79                            local objects.  If the get_value method of
80                            a generic object is called for a name that
81                            maps to a name/null pair, ISC_R_NOTFOUND is
82                            returned. */
83                         new = (omapi_value_t *)0;
84                         status = (omapi_value_new (&new, MDL));
85                         if (status != ISC_R_SUCCESS)
86                                 return status;
87                         omapi_data_string_reference (&new -> name, name, MDL);
88                         if (value)
89                                 omapi_typed_data_reference (&new -> value,
90                                                             value, MDL);
91
92                         omapi_value_dereference (&(g -> values [i]), MDL);
93                         status = (omapi_value_reference
94                                   (&(g -> values [i]), new, MDL));
95                         omapi_value_dereference (&new, MDL);
96                         g -> changed [i] = 1;
97                         return status;
98                 }
99                 /* Notice a free slot if we pass one. */
100                 else if (vfree == -1 && !g -> values [i])
101                         vfree = i;
102         }                       
103
104         /* If the name isn't already attached to this object, see if an
105            inner object has it. */
106         if (h -> inner && h -> inner -> type -> set_value) {
107                 status = ((*(h -> inner -> type -> set_value))
108                           (h -> inner, id, name, value));
109                 if (status != ISC_R_NOTFOUND)
110                         return status;
111         }
112
113         /* Okay, so it's a value that no inner object knows about, and
114            (implicitly, since the outer object set_value method would
115            have called this object's set_value method) it's an object that
116            no outer object knows about, it's this object's responsibility
117            to remember it - that's what generic objects do. */
118
119         /* Arrange for there to be space for the pointer to the new
120            name/value pair if necessary: */
121         if (vfree == -1) {
122                 vfree = g -> nvalues;
123                 if (vfree == g -> va_max) {
124                         if (g -> va_max)
125                                 vm_new = 2 * g -> va_max;
126                         else
127                                 vm_new = 10;
128                         va = dmalloc (vm_new * sizeof *va, MDL);
129                         if (!va)
130                                 return ISC_R_NOMEMORY;
131                         ca = dmalloc (vm_new * sizeof *ca, MDL);
132                         if (!ca) {
133                                 dfree (va, MDL);
134                                 return ISC_R_NOMEMORY;
135                         }
136                         if (g -> va_max) {
137                                 memcpy (va, g -> values,
138                                         g -> va_max * sizeof *va);
139                                 memcpy (ca, g -> changed,
140                                         g -> va_max * sizeof *ca);
141                         }
142                         memset (va + g -> va_max, 0,
143                                 (vm_new - g -> va_max) * sizeof *va);
144                         memset (ca + g -> va_max, 0,
145                                 (vm_new - g -> va_max) * sizeof *ca);
146                         if (g -> values)
147                                 dfree (g -> values, MDL);
148                         if (g -> changed)
149                                 dfree (g -> changed, MDL);
150                         g -> values = va;
151                         g -> changed = ca;
152                         g -> va_max = vm_new;
153                 }
154         }
155         status = omapi_value_new (&g -> values [vfree], MDL);
156         if (status != ISC_R_SUCCESS)
157                 return status;
158         omapi_data_string_reference (&g -> values [vfree] -> name,
159                                      name, MDL);
160         if (value)
161                 omapi_typed_data_reference
162                         (&g -> values [vfree] -> value, value, MDL);
163         g -> changed [vfree] = 1;
164         if (vfree == g -> nvalues)
165                 g -> nvalues++;
166         return ISC_R_SUCCESS;
167 }
168
169 isc_result_t omapi_generic_get_value (omapi_object_t *h,
170                                       omapi_object_t *id,
171                                       omapi_data_string_t *name,
172                                       omapi_value_t **value)
173 {
174         int i;
175         omapi_generic_object_t *g;
176
177         if (h -> type != omapi_type_generic)
178                 return ISC_R_INVALIDARG;
179         g = (omapi_generic_object_t *)h;
180         
181         /* Look up the specified name in our list of objects. */
182         for (i = 0; i < g -> nvalues; i++) {
183                 if (!g -> values[i])
184                         continue;
185                 if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
186                         /* If this is a name/null value pair, this is the
187                            same as if there were no value that matched
188                            the specified name, so return ISC_R_NOTFOUND. */
189                         if (!g -> values [i] -> value)
190                                 return ISC_R_NOTFOUND;
191                         /* Otherwise, return the name/value pair. */
192                         return omapi_value_reference (value,
193                                                       g -> values [i], MDL);
194                 }
195         }                       
196
197         if (h -> inner && h -> inner -> type -> get_value)
198                 return (*(h -> inner -> type -> get_value))
199                         (h -> inner, id, name, value);
200         return ISC_R_NOTFOUND;
201 }
202
203 isc_result_t omapi_generic_destroy (omapi_object_t *h,
204                                     const char *file, int line)
205 {
206         omapi_generic_object_t *g;
207         int i;
208
209         if (h -> type != omapi_type_generic)
210                 return ISC_R_UNEXPECTED;
211         g = (omapi_generic_object_t *)h;
212         
213         if (g -> values) {
214                 for (i = 0; i < g -> nvalues; i++) {
215                         if (g -> values [i])
216                                 omapi_value_dereference (&g -> values [i],
217                                                          file, line);
218                 }
219                 dfree (g -> values, file, line);
220                 dfree (g -> changed, file, line);
221                 g -> values = (omapi_value_t **)0;
222                 g -> changed = (u_int8_t *)0;
223                 g -> va_max = 0;
224         }
225
226         return ISC_R_SUCCESS;
227 }
228
229 isc_result_t omapi_generic_signal_handler (omapi_object_t *h,
230                                            const char *name, va_list ap)
231 {
232         if (h -> type != omapi_type_generic)
233                 return ISC_R_INVALIDARG;
234         
235         if (h -> inner && h -> inner -> type -> signal_handler)
236                 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
237                                                                   name, ap);
238         return ISC_R_NOTFOUND;
239 }
240
241 /* Write all the published values associated with the object through the
242    specified connection. */
243
244 isc_result_t omapi_generic_stuff_values (omapi_object_t *c,
245                                          omapi_object_t *id,
246                                          omapi_object_t *g)
247 {
248         omapi_generic_object_t *src;
249         int i;
250         isc_result_t status;
251
252         if (g -> type != omapi_type_generic)
253                 return ISC_R_INVALIDARG;
254         src = (omapi_generic_object_t *)g;
255         
256         for (i = 0; i < src -> nvalues; i++) {
257                 if (src -> values [i] && src -> values [i] -> name -> len &&
258                     src -> changed [i]) {
259                         status = (omapi_connection_put_uint16
260                                   (c, src -> values [i] -> name -> len));
261                         if (status != ISC_R_SUCCESS)
262                                 return status;
263                         status = (omapi_connection_copyin
264                                   (c, src -> values [i] -> name -> value,
265                                    src -> values [i] -> name -> len));
266                         if (status != ISC_R_SUCCESS)
267                                 return status;
268
269                         status = (omapi_connection_write_typed_data
270                                   (c, src -> values [i] -> value));
271                         if (status != ISC_R_SUCCESS)
272                                 return status;
273                 }
274         }                       
275
276         if (g -> inner && g -> inner -> type -> stuff_values)
277                 return (*(g -> inner -> type -> stuff_values)) (c, id,
278                                                                 g -> inner);
279         return ISC_R_SUCCESS;
280 }
281
282 /* Clear the changed flags on the object.   This has the effect that if
283    generic_stuff is called, any attributes that still have a cleared changed
284    flag aren't sent to the peer.   This also deletes any values that are
285    null, presuming that these have now been properly handled. */
286
287 isc_result_t omapi_generic_clear_flags (omapi_object_t *o)
288 {
289         int i;
290         isc_result_t status;
291         omapi_generic_object_t *g;
292
293         if (o -> type != omapi_type_generic)
294                 return ISC_R_INVALIDARG;
295         g = (omapi_generic_object_t *)o;
296
297         for (i = 0; i < g -> nvalues; i++) {
298                 g -> changed [i] = 0;
299                 if (g -> values [i] &&
300                     !g -> values [i] -> value)
301                         omapi_value_dereference (&g -> values [i], MDL);
302         }
303         return ISC_R_SUCCESS;
304 }