]>
Commit | Line | Data |
---|---|---|
61b844bf TL |
1 | /* generic.c |
2 | ||
3 | Subroutines that support the generic object. */ | |
4 | ||
5 | /* | |
edad9be5 | 6 | * Copyright (c) 2004-2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 7 | * Copyright (c) 1999-2003 by Internet Software Consortium |
61b844bf | 8 | * |
98311e4b DH |
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. | |
61b844bf | 12 | * |
98311e4b DH |
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. | |
61b844bf | 20 | * |
98311e4b DH |
21 | * Internet Systems Consortium, Inc. |
22 | * 950 Charter Street | |
23 | * Redwood City, CA 94063 | |
24 | * <info@isc.org> | |
2c85ac9b | 25 | * https://www.isc.org/ |
49733f31 | 26 | * |
61b844bf TL |
27 | */ |
28 | ||
fe5b0fdd DH |
29 | #include "dhcpd.h" |
30 | ||
6a4c4be8 | 31 | #include <omapip/omapip_p.h> |
61b844bf | 32 | |
20916cae TL |
33 | OMAPI_OBJECT_ALLOC (omapi_generic, |
34 | omapi_generic_object_t, omapi_type_generic) | |
35 | ||
4bd8800e TL |
36 | isc_result_t omapi_generic_new (omapi_object_t **gen, |
37 | const char *file, int line) | |
61b844bf | 38 | { |
20916cae TL |
39 | /* Backwards compatibility. */ |
40 | return omapi_generic_allocate ((omapi_generic_object_t **)gen, | |
41 | file, line); | |
61b844bf TL |
42 | } |
43 | ||
44 | isc_result_t omapi_generic_set_value (omapi_object_t *h, | |
45 | omapi_object_t *id, | |
46 | omapi_data_string_t *name, | |
47 | omapi_typed_data_t *value) | |
48 | { | |
49 | omapi_generic_object_t *g; | |
50 | omapi_value_t *new; | |
51 | omapi_value_t **va; | |
d758ad8c | 52 | u_int8_t *ca; |
61b844bf | 53 | int vm_new; |
d758ad8c | 54 | int i, vfree = -1; |
61b844bf TL |
55 | isc_result_t status; |
56 | ||
57 | if (h -> type != omapi_type_generic) | |
98bf1607 | 58 | return DHCP_R_INVALIDARG; |
61b844bf TL |
59 | g = (omapi_generic_object_t *)h; |
60 | ||
61 | /* See if there's already a value with this name attached to | |
62 | the generic object, and if so, replace the current value | |
63 | with the new one. */ | |
64 | for (i = 0; i < g -> nvalues; i++) { | |
65 | if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { | |
66 | /* There's an inconsistency here: the standard | |
67 | behaviour of a set_values method when | |
68 | passed a matching name and a null value is | |
69 | to delete the value associated with that | |
70 | name (where possible). In the generic | |
71 | object, we remember the name/null pair, | |
72 | because generic objects are generally used | |
73 | to pass messages around, and this is the | |
74 | way that remote entities delete values from | |
75 | local objects. If the get_value method of | |
76 | a generic object is called for a name that | |
77 | maps to a name/null pair, ISC_R_NOTFOUND is | |
78 | returned. */ | |
79 | new = (omapi_value_t *)0; | |
4bd8800e | 80 | status = (omapi_value_new (&new, MDL)); |
61b844bf TL |
81 | if (status != ISC_R_SUCCESS) |
82 | return status; | |
4bd8800e | 83 | omapi_data_string_reference (&new -> name, name, MDL); |
61b844bf | 84 | if (value) |
4bd8800e TL |
85 | omapi_typed_data_reference (&new -> value, |
86 | value, MDL); | |
61b844bf | 87 | |
4bd8800e | 88 | omapi_value_dereference (&(g -> values [i]), MDL); |
61b844bf | 89 | status = (omapi_value_reference |
4bd8800e TL |
90 | (&(g -> values [i]), new, MDL)); |
91 | omapi_value_dereference (&new, MDL); | |
d758ad8c | 92 | g -> changed [i] = 1; |
61b844bf TL |
93 | return status; |
94 | } | |
d758ad8c TL |
95 | /* Notice a free slot if we pass one. */ |
96 | else if (vfree == -1 && !g -> values [i]) | |
97 | vfree = i; | |
61b844bf TL |
98 | } |
99 | ||
100 | /* If the name isn't already attached to this object, see if an | |
101 | inner object has it. */ | |
581e37e4 | 102 | if (h -> inner && h -> inner -> type -> set_value) { |
61b844bf TL |
103 | status = ((*(h -> inner -> type -> set_value)) |
104 | (h -> inner, id, name, value)); | |
581e37e4 TL |
105 | if (status != ISC_R_NOTFOUND) |
106 | return status; | |
107 | } | |
61b844bf TL |
108 | |
109 | /* Okay, so it's a value that no inner object knows about, and | |
110 | (implicitly, since the outer object set_value method would | |
111 | have called this object's set_value method) it's an object that | |
112 | no outer object knows about, it's this object's responsibility | |
113 | to remember it - that's what generic objects do. */ | |
114 | ||
115 | /* Arrange for there to be space for the pointer to the new | |
116 | name/value pair if necessary: */ | |
d758ad8c TL |
117 | if (vfree == -1) { |
118 | vfree = g -> nvalues; | |
119 | if (vfree == g -> va_max) { | |
120 | if (g -> va_max) | |
121 | vm_new = 2 * g -> va_max; | |
122 | else | |
123 | vm_new = 10; | |
124 | va = dmalloc (vm_new * sizeof *va, MDL); | |
125 | if (!va) | |
126 | return ISC_R_NOMEMORY; | |
127 | ca = dmalloc (vm_new * sizeof *ca, MDL); | |
128 | if (!ca) { | |
129 | dfree (va, MDL); | |
130 | return ISC_R_NOMEMORY; | |
131 | } | |
132 | if (g -> va_max) { | |
133 | memcpy (va, g -> values, | |
134 | g -> va_max * sizeof *va); | |
135 | memcpy (ca, g -> changed, | |
136 | g -> va_max * sizeof *ca); | |
137 | } | |
138 | memset (va + g -> va_max, 0, | |
139 | (vm_new - g -> va_max) * sizeof *va); | |
140 | memset (ca + g -> va_max, 0, | |
141 | (vm_new - g -> va_max) * sizeof *ca); | |
142 | if (g -> values) | |
143 | dfree (g -> values, MDL); | |
144 | if (g -> changed) | |
145 | dfree (g -> changed, MDL); | |
146 | g -> values = va; | |
147 | g -> changed = ca; | |
148 | g -> va_max = vm_new; | |
149 | } | |
61b844bf | 150 | } |
d758ad8c | 151 | status = omapi_value_new (&g -> values [vfree], MDL); |
61b844bf TL |
152 | if (status != ISC_R_SUCCESS) |
153 | return status; | |
d758ad8c | 154 | omapi_data_string_reference (&g -> values [vfree] -> name, |
4bd8800e | 155 | name, MDL); |
61b844bf TL |
156 | if (value) |
157 | omapi_typed_data_reference | |
d758ad8c TL |
158 | (&g -> values [vfree] -> value, value, MDL); |
159 | g -> changed [vfree] = 1; | |
160 | if (vfree == g -> nvalues) | |
161 | g -> nvalues++; | |
61b844bf TL |
162 | return ISC_R_SUCCESS; |
163 | } | |
164 | ||
165 | isc_result_t omapi_generic_get_value (omapi_object_t *h, | |
166 | omapi_object_t *id, | |
167 | omapi_data_string_t *name, | |
168 | omapi_value_t **value) | |
169 | { | |
170 | int i; | |
171 | omapi_generic_object_t *g; | |
172 | ||
173 | if (h -> type != omapi_type_generic) | |
98bf1607 | 174 | return DHCP_R_INVALIDARG; |
61b844bf TL |
175 | g = (omapi_generic_object_t *)h; |
176 | ||
177 | /* Look up the specified name in our list of objects. */ | |
178 | for (i = 0; i < g -> nvalues; i++) { | |
98311e4b DH |
179 | if (!g -> values[i]) |
180 | continue; | |
61b844bf TL |
181 | if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { |
182 | /* If this is a name/null value pair, this is the | |
183 | same as if there were no value that matched | |
184 | the specified name, so return ISC_R_NOTFOUND. */ | |
185 | if (!g -> values [i] -> value) | |
186 | return ISC_R_NOTFOUND; | |
187 | /* Otherwise, return the name/value pair. */ | |
4bd8800e TL |
188 | return omapi_value_reference (value, |
189 | g -> values [i], MDL); | |
61b844bf TL |
190 | } |
191 | } | |
192 | ||
193 | if (h -> inner && h -> inner -> type -> get_value) | |
194 | return (*(h -> inner -> type -> get_value)) | |
195 | (h -> inner, id, name, value); | |
196 | return ISC_R_NOTFOUND; | |
197 | } | |
198 | ||
4bd8800e TL |
199 | isc_result_t omapi_generic_destroy (omapi_object_t *h, |
200 | const char *file, int line) | |
61b844bf TL |
201 | { |
202 | omapi_generic_object_t *g; | |
203 | int i; | |
204 | ||
205 | if (h -> type != omapi_type_generic) | |
206 | return ISC_R_UNEXPECTED; | |
207 | g = (omapi_generic_object_t *)h; | |
208 | ||
209 | if (g -> values) { | |
210 | for (i = 0; i < g -> nvalues; i++) { | |
211 | if (g -> values [i]) | |
212 | omapi_value_dereference (&g -> values [i], | |
4bd8800e | 213 | file, line); |
61b844bf | 214 | } |
4bd8800e | 215 | dfree (g -> values, file, line); |
d758ad8c | 216 | dfree (g -> changed, file, line); |
61b844bf | 217 | g -> values = (omapi_value_t **)0; |
d758ad8c | 218 | g -> changed = (u_int8_t *)0; |
61b844bf TL |
219 | g -> va_max = 0; |
220 | } | |
221 | ||
222 | return ISC_R_SUCCESS; | |
223 | } | |
224 | ||
225 | isc_result_t omapi_generic_signal_handler (omapi_object_t *h, | |
b1b7b521 | 226 | const char *name, va_list ap) |
61b844bf TL |
227 | { |
228 | if (h -> type != omapi_type_generic) | |
98bf1607 | 229 | return DHCP_R_INVALIDARG; |
61b844bf TL |
230 | |
231 | if (h -> inner && h -> inner -> type -> signal_handler) | |
232 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
233 | name, ap); | |
234 | return ISC_R_NOTFOUND; | |
235 | } | |
236 | ||
237 | /* Write all the published values associated with the object through the | |
238 | specified connection. */ | |
239 | ||
240 | isc_result_t omapi_generic_stuff_values (omapi_object_t *c, | |
241 | omapi_object_t *id, | |
242 | omapi_object_t *g) | |
243 | { | |
244 | omapi_generic_object_t *src; | |
245 | int i; | |
246 | isc_result_t status; | |
247 | ||
248 | if (g -> type != omapi_type_generic) | |
98bf1607 | 249 | return DHCP_R_INVALIDARG; |
61b844bf TL |
250 | src = (omapi_generic_object_t *)g; |
251 | ||
252 | for (i = 0; i < src -> nvalues; i++) { | |
d758ad8c TL |
253 | if (src -> values [i] && src -> values [i] -> name -> len && |
254 | src -> changed [i]) { | |
61b844bf TL |
255 | status = (omapi_connection_put_uint16 |
256 | (c, src -> values [i] -> name -> len)); | |
257 | if (status != ISC_R_SUCCESS) | |
258 | return status; | |
581e37e4 TL |
259 | status = (omapi_connection_copyin |
260 | (c, src -> values [i] -> name -> value, | |
61b844bf TL |
261 | src -> values [i] -> name -> len)); |
262 | if (status != ISC_R_SUCCESS) | |
263 | return status; | |
264 | ||
265 | status = (omapi_connection_write_typed_data | |
266 | (c, src -> values [i] -> value)); | |
267 | if (status != ISC_R_SUCCESS) | |
268 | return status; | |
269 | } | |
270 | } | |
271 | ||
272 | if (g -> inner && g -> inner -> type -> stuff_values) | |
273 | return (*(g -> inner -> type -> stuff_values)) (c, id, | |
274 | g -> inner); | |
275 | return ISC_R_SUCCESS; | |
276 | } | |
277 | ||
d758ad8c TL |
278 | /* Clear the changed flags on the object. This has the effect that if |
279 | generic_stuff is called, any attributes that still have a cleared changed | |
280 | flag aren't sent to the peer. This also deletes any values that are | |
281 | null, presuming that these have now been properly handled. */ | |
282 | ||
283 | isc_result_t omapi_generic_clear_flags (omapi_object_t *o) | |
284 | { | |
285 | int i; | |
d758ad8c TL |
286 | omapi_generic_object_t *g; |
287 | ||
288 | if (o -> type != omapi_type_generic) | |
98bf1607 | 289 | return DHCP_R_INVALIDARG; |
d758ad8c TL |
290 | g = (omapi_generic_object_t *)o; |
291 | ||
292 | for (i = 0; i < g -> nvalues; i++) { | |
293 | g -> changed [i] = 0; | |
294 | if (g -> values [i] && | |
295 | !g -> values [i] -> value) | |
296 | omapi_value_dereference (&g -> values [i], MDL); | |
297 | } | |
298 | return ISC_R_SUCCESS; | |
299 | } |