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