]>
Commit | Line | Data |
---|---|---|
61b844bf TL |
1 | /* connection.c |
2 | ||
3 | Subroutines for dealing with connections. */ | |
4 | ||
5 | /* | |
edad9be5 | 6 | * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC") |
23d39ae2 | 7 | * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 8 | * Copyright (c) 1999-2003 by Internet Software Consortium |
61b844bf | 9 | * |
98311e4b DH |
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. | |
61b844bf | 13 | * |
98311e4b DH |
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. | |
61b844bf | 21 | * |
98311e4b DH |
22 | * Internet Systems Consortium, Inc. |
23 | * 950 Charter Street | |
24 | * Redwood City, CA 94063 | |
25 | * <info@isc.org> | |
2c85ac9b | 26 | * https://www.isc.org/ |
49733f31 | 27 | * |
61b844bf TL |
28 | */ |
29 | ||
fe5b0fdd DH |
30 | #include "dhcpd.h" |
31 | ||
6a4c4be8 | 32 | #include <omapip/omapip_p.h> |
d05243c1 | 33 | #include <arpa/inet.h> |
8c3c6552 | 34 | #include <arpa/nameser.h> |
fe5b0fdd | 35 | #include <errno.h> |
61b844bf | 36 | |
ef5cc183 TL |
37 | #if defined (TRACING) |
38 | static void trace_connect_input (trace_type_t *, unsigned, char *); | |
39 | static void trace_connect_stop (trace_type_t *); | |
40 | static void trace_disconnect_input (trace_type_t *, unsigned, char *); | |
41 | static void trace_disconnect_stop (trace_type_t *); | |
42 | trace_type_t *trace_connect; | |
43 | trace_type_t *trace_disconnect; | |
44 | extern omapi_array_t *trace_listeners; | |
45 | #endif | |
aaa98d8c | 46 | static isc_result_t omapi_connection_connect_internal (omapi_object_t *); |
ef5cc183 | 47 | |
20916cae TL |
48 | OMAPI_OBJECT_ALLOC (omapi_connection, |
49 | omapi_connection_object_t, omapi_type_connection) | |
50 | ||
61b844bf | 51 | isc_result_t omapi_connect (omapi_object_t *c, |
b1b7b521 | 52 | const char *server_name, |
d9eefc5d | 53 | unsigned port) |
61b844bf TL |
54 | { |
55 | struct hostent *he; | |
fc24e951 TL |
56 | unsigned i, hix; |
57 | omapi_addr_list_t *addrs = (omapi_addr_list_t *)0; | |
58 | struct in_addr foo; | |
59 | isc_result_t status; | |
60 | ||
e11a162f DN |
61 | #ifdef DEBUG_PROTOCOL |
62 | log_debug ("omapi_connect(%s, port=%d)", server_name, port); | |
63 | #endif | |
64 | ||
fc24e951 TL |
65 | if (!inet_aton (server_name, &foo)) { |
66 | /* If we didn't get a numeric address, try for a domain | |
67 | name. It's okay for this call to block. */ | |
68 | he = gethostbyname (server_name); | |
69 | if (!he) | |
98bf1607 | 70 | return DHCP_R_HOSTUNKNOWN; |
fc24e951 TL |
71 | for (i = 0; he -> h_addr_list [i]; i++) |
72 | ; | |
73 | if (i == 0) | |
98bf1607 | 74 | return DHCP_R_HOSTUNKNOWN; |
fc24e951 TL |
75 | hix = i; |
76 | ||
20916cae TL |
77 | status = omapi_addr_list_new (&addrs, hix, MDL); |
78 | if (status != ISC_R_SUCCESS) | |
79 | return status; | |
fc24e951 TL |
80 | for (i = 0; i < hix; i++) { |
81 | addrs -> addresses [i].addrtype = he -> h_addrtype; | |
82 | addrs -> addresses [i].addrlen = he -> h_length; | |
83 | memcpy (addrs -> addresses [i].address, | |
84 | he -> h_addr_list [i], | |
85 | (unsigned)he -> h_length); | |
86 | addrs -> addresses [i].port = port; | |
87 | } | |
88 | } else { | |
20916cae TL |
89 | status = omapi_addr_list_new (&addrs, 1, MDL); |
90 | if (status != ISC_R_SUCCESS) | |
91 | return status; | |
fc24e951 TL |
92 | addrs -> addresses [0].addrtype = AF_INET; |
93 | addrs -> addresses [0].addrlen = sizeof foo; | |
94 | memcpy (addrs -> addresses [0].address, &foo, sizeof foo); | |
95 | addrs -> addresses [0].port = port; | |
fc24e951 TL |
96 | } |
97 | status = omapi_connect_list (c, addrs, (omapi_addr_t *)0); | |
98 | omapi_addr_list_dereference (&addrs, MDL); | |
99 | return status; | |
100 | } | |
101 | ||
102 | isc_result_t omapi_connect_list (omapi_object_t *c, | |
103 | omapi_addr_list_t *remote_addrs, | |
104 | omapi_addr_t *local_addr) | |
105 | { | |
61b844bf TL |
106 | isc_result_t status; |
107 | omapi_connection_object_t *obj; | |
2f11d5e1 | 108 | int flag; |
fc24e951 | 109 | struct sockaddr_in local_sin; |
61b844bf | 110 | |
20916cae TL |
111 | obj = (omapi_connection_object_t *)0; |
112 | status = omapi_connection_allocate (&obj, MDL); | |
113 | if (status != ISC_R_SUCCESS) | |
114 | return status; | |
61b844bf TL |
115 | |
116 | status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj, | |
4bd8800e | 117 | MDL); |
61b844bf | 118 | if (status != ISC_R_SUCCESS) { |
20916cae | 119 | omapi_connection_dereference (&obj, MDL); |
61b844bf TL |
120 | return status; |
121 | } | |
4bd8800e | 122 | status = omapi_object_reference (&obj -> inner, c, MDL); |
61b844bf | 123 | if (status != ISC_R_SUCCESS) { |
20916cae | 124 | omapi_connection_dereference (&obj, MDL); |
61b844bf TL |
125 | return status; |
126 | } | |
127 | ||
3ce5a420 TL |
128 | /* Store the address list on the object. */ |
129 | omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL); | |
130 | obj -> cptr = 0; | |
131 | obj -> state = omapi_connection_unconnected; | |
2f11d5e1 | 132 | |
3ce5a420 TL |
133 | #if defined (TRACING) |
134 | /* If we're playing back, don't actually try to connect - just leave | |
135 | the object available for a subsequent connect or disconnect. */ | |
136 | if (!trace_playback ()) { | |
137 | #endif | |
138 | /* Create a socket on which to communicate. */ | |
139 | obj -> socket = | |
140 | socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); | |
141 | if (obj -> socket < 0) { | |
20916cae | 142 | omapi_connection_dereference (&obj, MDL); |
3ce5a420 TL |
143 | if (errno == EMFILE || errno == ENFILE |
144 | || errno == ENOBUFS) | |
145 | return ISC_R_NORESOURCES; | |
146 | return ISC_R_UNEXPECTED; | |
fc24e951 | 147 | } |
3ce5a420 TL |
148 | |
149 | /* Set up the local address, if any. */ | |
150 | if (local_addr) { | |
151 | /* Only do TCPv4 so far. */ | |
152 | if (local_addr -> addrtype != AF_INET) { | |
21f3982a | 153 | close(obj->socket); |
3ce5a420 | 154 | omapi_connection_dereference (&obj, MDL); |
98bf1607 | 155 | return DHCP_R_INVALIDARG; |
3ce5a420 TL |
156 | } |
157 | local_sin.sin_port = htons (local_addr -> port); | |
158 | memcpy (&local_sin.sin_addr, | |
159 | local_addr -> address, | |
160 | local_addr -> addrlen); | |
fc24e951 | 161 | #if defined (HAVE_SA_LEN) |
3ce5a420 | 162 | local_sin.sin_len = sizeof local_addr; |
fc24e951 | 163 | #endif |
3ce5a420 TL |
164 | local_sin.sin_family = AF_INET; |
165 | memset (&local_sin.sin_zero, 0, | |
166 | sizeof local_sin.sin_zero); | |
167 | ||
168 | if (bind (obj -> socket, (struct sockaddr *)&local_sin, | |
169 | sizeof local_sin) < 0) { | |
06eb8bab SK |
170 | omapi_connection_object_t **objp = &obj; |
171 | omapi_object_t **o = (omapi_object_t **)objp; | |
21f3982a | 172 | close(obj->socket); |
06eb8bab | 173 | omapi_object_dereference(o, MDL); |
3ce5a420 TL |
174 | if (errno == EADDRINUSE) |
175 | return ISC_R_ADDRINUSE; | |
176 | if (errno == EADDRNOTAVAIL) | |
177 | return ISC_R_ADDRNOTAVAIL; | |
178 | if (errno == EACCES) | |
179 | return ISC_R_NOPERM; | |
180 | return ISC_R_UNEXPECTED; | |
181 | } | |
d758ad8c | 182 | obj -> local_addr = local_sin; |
fc24e951 | 183 | } |
fc24e951 | 184 | |
fe5b0fdd | 185 | #if defined(F_SETFD) |
3ce5a420 TL |
186 | if (fcntl (obj -> socket, F_SETFD, 1) < 0) { |
187 | close (obj -> socket); | |
188 | omapi_connection_dereference (&obj, MDL); | |
189 | return ISC_R_UNEXPECTED; | |
190 | } | |
892aa61a TL |
191 | #endif |
192 | ||
3ce5a420 TL |
193 | /* Set the SO_REUSEADDR flag (this should not fail). */ |
194 | flag = 1; | |
195 | if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR, | |
196 | (char *)&flag, sizeof flag) < 0) { | |
197 | omapi_connection_dereference (&obj, MDL); | |
198 | return ISC_R_UNEXPECTED; | |
199 | } | |
61b844bf | 200 | |
3ce5a420 TL |
201 | /* Set the file to nonblocking mode. */ |
202 | if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) { | |
203 | omapi_connection_dereference (&obj, MDL); | |
204 | return ISC_R_UNEXPECTED; | |
205 | } | |
61b844bf | 206 | |
3004baba SR |
207 | #ifdef SO_NOSIGPIPE |
208 | /* | |
209 | * If available stop the OS from killing our | |
210 | * program on a SIGPIPE failure | |
211 | */ | |
212 | flag = 1; | |
213 | if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE, | |
214 | (char *)&flag, sizeof(flag)) < 0) { | |
215 | omapi_connection_dereference (&obj, MDL); | |
216 | return ISC_R_UNEXPECTED; | |
217 | } | |
218 | #endif | |
219 | ||
3ce5a420 TL |
220 | status = (omapi_register_io_object |
221 | ((omapi_object_t *)obj, | |
222 | 0, omapi_connection_writefd, | |
223 | 0, omapi_connection_connect, | |
224 | omapi_connection_reaper)); | |
225 | if (status != ISC_R_SUCCESS) | |
226 | goto out; | |
aaa98d8c TL |
227 | status = omapi_connection_connect_internal ((omapi_object_t *) |
228 | obj); | |
199f0b8a SR |
229 | /* |
230 | * inprogress is the same as success but used | |
231 | * to indicate to the dispatch code that we should | |
232 | * mark the socket as requiring more attention. | |
233 | * Routines calling this function should handle | |
234 | * success properly. | |
235 | */ | |
236 | if (status == ISC_R_INPROGRESS) { | |
237 | status = ISC_R_SUCCESS; | |
238 | } | |
3ce5a420 TL |
239 | #if defined (TRACING) |
240 | } | |
241 | omapi_connection_register (obj, MDL); | |
242 | #endif | |
61b844bf | 243 | |
67a291cf | 244 | out: |
20916cae | 245 | omapi_connection_dereference (&obj, MDL); |
fc24e951 | 246 | return status; |
61b844bf TL |
247 | } |
248 | ||
3ce5a420 | 249 | #if defined (TRACING) |
ef5cc183 | 250 | omapi_array_t *omapi_connections; |
3ce5a420 | 251 | |
a7394d15 | 252 | OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t) |
3ce5a420 | 253 | |
ef5cc183 TL |
254 | void omapi_connection_trace_setup (void) { |
255 | trace_connect = trace_type_register ("connect", (void *)0, | |
256 | trace_connect_input, | |
257 | trace_connect_stop, MDL); | |
258 | trace_disconnect = trace_type_register ("disconnect", (void *)0, | |
259 | trace_disconnect_input, | |
260 | trace_disconnect_stop, MDL); | |
261 | } | |
262 | ||
3ce5a420 TL |
263 | void omapi_connection_register (omapi_connection_object_t *obj, |
264 | const char *file, int line) | |
265 | { | |
266 | isc_result_t status; | |
ef5cc183 TL |
267 | trace_iov_t iov [6]; |
268 | int iov_count = 0; | |
269 | int32_t connect_index, listener_index; | |
270 | static int32_t index; | |
3ce5a420 TL |
271 | |
272 | if (!omapi_connections) { | |
273 | status = omapi_connection_array_allocate (&omapi_connections, | |
274 | file, line); | |
275 | if (status != ISC_R_SUCCESS) | |
276 | return; | |
277 | } | |
278 | ||
ef5cc183 | 279 | status = omapi_connection_array_extend (omapi_connections, obj, |
2844788f | 280 | (int *)0, file, line); |
ef5cc183 TL |
281 | if (status != ISC_R_SUCCESS) { |
282 | obj -> index = -1; | |
283 | return; | |
284 | } | |
285 | ||
31bbee78 | 286 | #if defined (TRACING) |
ef5cc183 TL |
287 | if (trace_record ()) { |
288 | /* Connection registration packet: | |
289 | ||
290 | int32_t index | |
291 | int32_t listener_index [-1 means no listener] | |
292 | u_int16_t remote_port | |
293 | u_int16_t local_port | |
294 | u_int32_t remote_addr | |
295 | u_int32_t local_addr */ | |
296 | ||
297 | connect_index = htonl (index); | |
298 | index++; | |
299 | if (obj -> listener) | |
300 | listener_index = htonl (obj -> listener -> index); | |
301 | else | |
302 | listener_index = htonl (-1); | |
303 | iov [iov_count].buf = (char *)&connect_index; | |
304 | iov [iov_count++].len = sizeof connect_index; | |
305 | iov [iov_count].buf = (char *)&listener_index; | |
306 | iov [iov_count++].len = sizeof listener_index; | |
307 | iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port; | |
308 | iov [iov_count++].len = sizeof obj -> remote_addr.sin_port; | |
309 | iov [iov_count].buf = (char *)&obj -> local_addr.sin_port; | |
310 | iov [iov_count++].len = sizeof obj -> local_addr.sin_port; | |
311 | iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr; | |
312 | iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr; | |
313 | iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr; | |
314 | iov [iov_count++].len = sizeof obj -> local_addr.sin_addr; | |
315 | ||
316 | status = trace_write_packet_iov (trace_connect, | |
317 | iov_count, iov, file, line); | |
318 | } | |
31bbee78 | 319 | #endif |
3ce5a420 | 320 | } |
ef5cc183 TL |
321 | |
322 | static void trace_connect_input (trace_type_t *ttype, | |
323 | unsigned length, char *buf) | |
324 | { | |
325 | struct sockaddr_in remote, local; | |
326 | int32_t connect_index, listener_index; | |
327 | char *s = buf; | |
328 | omapi_connection_object_t *obj; | |
329 | isc_result_t status; | |
d758ad8c | 330 | int i; |
ef5cc183 TL |
331 | |
332 | if (length != ((sizeof connect_index) + | |
333 | (sizeof remote.sin_port) + | |
334 | (sizeof remote.sin_addr)) * 2) { | |
335 | log_error ("Trace connect: invalid length %d", length); | |
336 | return; | |
337 | } | |
338 | ||
339 | memset (&remote, 0, sizeof remote); | |
340 | memset (&local, 0, sizeof local); | |
d758ad8c | 341 | memcpy (&connect_index, s, sizeof connect_index); |
ef5cc183 | 342 | s += sizeof connect_index; |
d758ad8c | 343 | memcpy (&listener_index, s, sizeof listener_index); |
ef5cc183 TL |
344 | s += sizeof listener_index; |
345 | memcpy (&remote.sin_port, s, sizeof remote.sin_port); | |
346 | s += sizeof remote.sin_port; | |
347 | memcpy (&local.sin_port, s, sizeof local.sin_port); | |
348 | s += sizeof local.sin_port; | |
349 | memcpy (&remote.sin_addr, s, sizeof remote.sin_addr); | |
350 | s += sizeof remote.sin_addr; | |
351 | memcpy (&local.sin_addr, s, sizeof local.sin_addr); | |
352 | s += sizeof local.sin_addr; | |
dc9d7b08 | 353 | POST(s); |
ef5cc183 TL |
354 | |
355 | connect_index = ntohl (connect_index); | |
356 | listener_index = ntohl (listener_index); | |
357 | ||
358 | /* If this was a connect to a listener, then we just slap together | |
359 | a new connection. */ | |
360 | if (listener_index != -1) { | |
361 | omapi_listener_object_t *listener; | |
362 | listener = (omapi_listener_object_t *)0; | |
363 | omapi_array_foreach_begin (trace_listeners, | |
364 | omapi_listener_object_t, lp) { | |
365 | if (lp -> address.sin_port == local.sin_port) { | |
366 | omapi_listener_reference (&listener, lp, MDL); | |
367 | omapi_listener_dereference (&lp, MDL); | |
368 | break; | |
d758ad8c | 369 | } |
ef5cc183 TL |
370 | } omapi_array_foreach_end (trace_listeners, |
371 | omapi_listener_object_t, lp); | |
372 | if (!listener) { | |
5f23e895 | 373 | log_error ("%s%ld, addr %s, port %d", |
ef5cc183 | 374 | "Spurious traced listener connect - index ", |
5f23e895 DN |
375 | (long int)listener_index, |
376 | inet_ntoa (local.sin_addr), | |
ef5cc183 TL |
377 | ntohs (local.sin_port)); |
378 | return; | |
379 | } | |
380 | obj = (omapi_connection_object_t *)0; | |
381 | status = omapi_listener_connect (&obj, listener, -1, &remote); | |
382 | if (status != ISC_R_SUCCESS) { | |
383 | log_error ("traced listener connect: %s", | |
384 | isc_result_totext (status)); | |
385 | } | |
386 | if (obj) | |
387 | omapi_connection_dereference (&obj, MDL); | |
388 | omapi_listener_dereference (&listener, MDL); | |
389 | return; | |
390 | } | |
391 | ||
392 | /* Find the matching connect object, if there is one. */ | |
393 | omapi_array_foreach_begin (omapi_connections, | |
394 | omapi_connection_object_t, lp) { | |
0f750c4f SR |
395 | for (i = 0; (lp->connect_list && |
396 | i < lp->connect_list->count); i++) { | |
d758ad8c | 397 | if (!memcmp (&remote.sin_addr, |
0f750c4f | 398 | &lp->connect_list->addresses[i].address, |
d758ad8c TL |
399 | sizeof remote.sin_addr) && |
400 | (ntohs (remote.sin_port) == | |
0f750c4f SR |
401 | lp->connect_list->addresses[i].port)) { |
402 | lp->state = omapi_connection_connected; | |
403 | lp->remote_addr = remote; | |
404 | lp->remote_addr.sin_family = AF_INET; | |
405 | omapi_addr_list_dereference(&lp->connect_list, MDL); | |
406 | lp->index = connect_index; | |
407 | status = omapi_signal_in((omapi_object_t *)lp, | |
408 | "connect"); | |
409 | omapi_connection_dereference (&lp, MDL); | |
410 | return; | |
411 | } | |
ef5cc183 TL |
412 | } |
413 | } omapi_array_foreach_end (omapi_connections, | |
414 | omapi_connection_object_t, lp); | |
415 | ||
5f23e895 DN |
416 | log_error ("Spurious traced connect - index %ld, addr %s, port %d", |
417 | (long int)connect_index, inet_ntoa (remote.sin_addr), | |
ef5cc183 TL |
418 | ntohs (remote.sin_port)); |
419 | return; | |
420 | } | |
421 | ||
422 | static void trace_connect_stop (trace_type_t *ttype) { } | |
423 | ||
424 | static void trace_disconnect_input (trace_type_t *ttype, | |
425 | unsigned length, char *buf) | |
426 | { | |
427 | int32_t *index; | |
428 | if (length != sizeof *index) { | |
429 | log_error ("trace disconnect: wrong length %d", length); | |
430 | return; | |
431 | } | |
432 | ||
433 | index = (int32_t *)buf; | |
434 | ||
435 | omapi_array_foreach_begin (omapi_connections, | |
436 | omapi_connection_object_t, lp) { | |
437 | if (lp -> index == ntohl (*index)) { | |
438 | omapi_disconnect ((omapi_object_t *)lp, 1); | |
439 | omapi_connection_dereference (&lp, MDL); | |
440 | return; | |
441 | } | |
442 | } omapi_array_foreach_end (omapi_connections, | |
443 | omapi_connection_object_t, lp); | |
444 | ||
5f23e895 DN |
445 | log_error ("trace disconnect: no connection matching index %ld", |
446 | (long int)ntohl (*index)); | |
ef5cc183 TL |
447 | } |
448 | ||
449 | static void trace_disconnect_stop (trace_type_t *ttype) { } | |
3ce5a420 TL |
450 | #endif |
451 | ||
61b844bf TL |
452 | /* Disconnect a connection object from the remote end. If force is nonzero, |
453 | close the connection immediately. Otherwise, shut down the receiving end | |
454 | but allow any unsent data to be sent before actually closing the socket. */ | |
455 | ||
456 | isc_result_t omapi_disconnect (omapi_object_t *h, | |
457 | int force) | |
458 | { | |
459 | omapi_connection_object_t *c; | |
460 | ||
e11a162f DN |
461 | #ifdef DEBUG_PROTOCOL |
462 | log_debug ("omapi_disconnect(%s)", force ? "force" : ""); | |
463 | #endif | |
464 | ||
61b844bf TL |
465 | c = (omapi_connection_object_t *)h; |
466 | if (c -> type != omapi_type_connection) | |
98bf1607 | 467 | return DHCP_R_INVALIDARG; |
61b844bf | 468 | |
ef5cc183 TL |
469 | #if defined (TRACING) |
470 | if (trace_record ()) { | |
66cebfcb | 471 | isc_result_t status; |
ef5cc183 TL |
472 | int32_t index; |
473 | ||
474 | index = htonl (c -> index); | |
475 | status = trace_write_packet (trace_disconnect, | |
476 | sizeof index, (char *)&index, | |
477 | MDL); | |
478 | if (status != ISC_R_SUCCESS) { | |
479 | trace_stop (); | |
480 | log_error ("trace_write_packet: %s", | |
481 | isc_result_totext (status)); | |
482 | } | |
483 | } | |
484 | if (!trace_playback ()) { | |
485 | #endif | |
486 | if (!force) { | |
487 | /* If we're already disconnecting, we don't have to do | |
488 | anything. */ | |
489 | if (c -> state == omapi_connection_disconnecting) | |
61b844bf | 490 | return ISC_R_SUCCESS; |
ef5cc183 TL |
491 | |
492 | /* Try to shut down the socket - this sends a FIN to | |
493 | the remote end, so that it won't send us any more | |
494 | data. If the shutdown succeeds, and we still | |
495 | have bytes left to write, defer closing the socket | |
496 | until that's done. */ | |
497 | if (!shutdown (c -> socket, SHUT_RD)) { | |
498 | if (c -> out_bytes > 0) { | |
499 | c -> state = | |
500 | omapi_connection_disconnecting; | |
501 | return ISC_R_SUCCESS; | |
502 | } | |
61b844bf TL |
503 | } |
504 | } | |
ef5cc183 TL |
505 | close (c -> socket); |
506 | #if defined (TRACING) | |
61b844bf | 507 | } |
ef5cc183 | 508 | #endif |
61b844bf TL |
509 | c -> state = omapi_connection_closed; |
510 | ||
98bf1607 SR |
511 | #if 0 |
512 | /* | |
513 | * Disconnecting from the I/O object seems incorrect as it doesn't | |
514 | * cause the I/O object to be cleaned and released. Previous to | |
515 | * using the isc socket library this wouldn't have caused a problem | |
516 | * with the socket library we would have a reference to a closed | |
517 | * socket. Instead we now do an unregister to properly free the | |
518 | * I/O object. | |
519 | */ | |
520 | ||
61b844bf | 521 | /* Disconnect from I/O object, if any. */ |
ee3aeca6 TL |
522 | if (h -> outer) { |
523 | if (h -> outer -> inner) | |
524 | omapi_object_dereference (&h -> outer -> inner, MDL); | |
4bd8800e | 525 | omapi_object_dereference (&h -> outer, MDL); |
ee3aeca6 | 526 | } |
98bf1607 SR |
527 | #else |
528 | if (h->outer) { | |
529 | omapi_unregister_io_object(h); | |
530 | } | |
531 | #endif | |
61b844bf TL |
532 | |
533 | /* If whatever created us registered a signal handler, send it | |
534 | a disconnect signal. */ | |
535 | omapi_signal (h, "disconnect", h); | |
4619c0a2 DH |
536 | |
537 | /* Disconnect from protocol object, if any. */ | |
538 | if (h->inner != NULL) { | |
539 | if (h->inner->outer != NULL) { | |
540 | omapi_object_dereference(&h->inner->outer, MDL); | |
541 | } | |
542 | omapi_object_dereference(&h->inner, MDL); | |
543 | } | |
544 | ||
545 | /* XXX: the code to free buffers should be in the dereference | |
546 | function, but there is no special-purpose function to | |
547 | dereference connections, so these just get leaked */ | |
548 | /* Free any buffers */ | |
549 | if (c->inbufs != NULL) { | |
550 | omapi_buffer_dereference(&c->inbufs, MDL); | |
551 | } | |
552 | c->in_bytes = 0; | |
553 | if (c->outbufs != NULL) { | |
554 | omapi_buffer_dereference(&c->outbufs, MDL); | |
555 | } | |
556 | c->out_bytes = 0; | |
557 | ||
61b844bf TL |
558 | return ISC_R_SUCCESS; |
559 | } | |
560 | ||
b1b7b521 | 561 | isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes) |
61b844bf TL |
562 | { |
563 | omapi_connection_object_t *c; | |
564 | ||
565 | if (h -> type != omapi_type_connection) | |
98bf1607 | 566 | return DHCP_R_INVALIDARG; |
61b844bf TL |
567 | c = (omapi_connection_object_t *)h; |
568 | ||
569 | c -> bytes_needed = bytes; | |
570 | if (c -> bytes_needed <= c -> in_bytes) { | |
571 | return ISC_R_SUCCESS; | |
572 | } | |
98bf1607 | 573 | return DHCP_R_NOTYET; |
61b844bf TL |
574 | } |
575 | ||
576 | /* Return the socket on which the dispatcher should wait for readiness | |
98bf1607 | 577 | to read, for a connection object. */ |
61b844bf TL |
578 | int omapi_connection_readfd (omapi_object_t *h) |
579 | { | |
580 | omapi_connection_object_t *c; | |
581 | if (h -> type != omapi_type_connection) | |
582 | return -1; | |
583 | c = (omapi_connection_object_t *)h; | |
584 | if (c -> state != omapi_connection_connected) | |
585 | return -1; | |
61b844bf TL |
586 | return c -> socket; |
587 | } | |
588 | ||
98bf1607 SR |
589 | /* |
590 | * Return the socket on which the dispatcher should wait for readiness | |
591 | * to write, for a connection object. When bytes are buffered we should | |
592 | * also poke the dispatcher to tell it to start or re-start watching the | |
593 | * socket. | |
594 | */ | |
61b844bf TL |
595 | int omapi_connection_writefd (omapi_object_t *h) |
596 | { | |
597 | omapi_connection_object_t *c; | |
598 | if (h -> type != omapi_type_connection) | |
599 | return -1; | |
2f11d5e1 | 600 | c = (omapi_connection_object_t *)h; |
98bf1607 | 601 | return c->socket; |
61b844bf TL |
602 | } |
603 | ||
fc24e951 | 604 | isc_result_t omapi_connection_connect (omapi_object_t *h) |
aaa98d8c TL |
605 | { |
606 | isc_result_t status; | |
607 | ||
8fa0112d | 608 | /* |
23d39ae2 SR |
609 | * We use the INPROGRESS status to indicate that |
610 | * we want more from the socket. In this case we | |
611 | * have now connected and are trying to write to | |
612 | * the socket for the first time. For the signaling | |
613 | * code this is the same as a SUCCESS so we don't | |
614 | * pass it on as a signal. | |
8fa0112d | 615 | */ |
23d39ae2 | 616 | status = omapi_connection_connect_internal (h); |
8fa0112d SR |
617 | if (status == ISC_R_INPROGRESS) |
618 | return ISC_R_INPROGRESS; | |
619 | ||
23d39ae2 SR |
620 | if (status != ISC_R_SUCCESS) |
621 | omapi_signal (h, "status", status); | |
622 | ||
aaa98d8c TL |
623 | return ISC_R_SUCCESS; |
624 | } | |
625 | ||
626 | static isc_result_t omapi_connection_connect_internal (omapi_object_t *h) | |
fc24e951 | 627 | { |
0f750c4f | 628 | int error = 0; |
fc24e951 | 629 | omapi_connection_object_t *c; |
fe5b0fdd | 630 | socklen_t sl; |
fc24e951 TL |
631 | isc_result_t status; |
632 | ||
633 | if (h -> type != omapi_type_connection) | |
98bf1607 | 634 | return DHCP_R_INVALIDARG; |
fc24e951 TL |
635 | c = (omapi_connection_object_t *)h; |
636 | ||
637 | if (c -> state == omapi_connection_connecting) { | |
638 | sl = sizeof error; | |
639 | if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR, | |
165bce70 | 640 | (char *)&error, &sl) < 0) { |
fc24e951 TL |
641 | omapi_disconnect (h, 1); |
642 | return ISC_R_SUCCESS; | |
643 | } | |
d86ec998 | 644 | if (!error) |
fc24e951 TL |
645 | c -> state = omapi_connection_connected; |
646 | } | |
647 | if (c -> state == omapi_connection_connecting || | |
648 | c -> state == omapi_connection_unconnected) { | |
649 | if (c -> cptr >= c -> connect_list -> count) { | |
aaa98d8c TL |
650 | switch (error) { |
651 | case ECONNREFUSED: | |
652 | status = ISC_R_CONNREFUSED; | |
653 | break; | |
654 | case ENETUNREACH: | |
655 | status = ISC_R_NETUNREACH; | |
656 | break; | |
657 | default: | |
658 | status = uerr2isc (error); | |
659 | break; | |
660 | } | |
fc24e951 | 661 | omapi_disconnect (h, 1); |
aaa98d8c | 662 | return status; |
fc24e951 TL |
663 | } |
664 | ||
665 | if (c -> connect_list -> addresses [c -> cptr].addrtype != | |
666 | AF_INET) { | |
667 | omapi_disconnect (h, 1); | |
98bf1607 | 668 | return DHCP_R_INVALIDARG; |
fc24e951 TL |
669 | } |
670 | ||
671 | memcpy (&c -> remote_addr.sin_addr, | |
672 | &c -> connect_list -> addresses [c -> cptr].address, | |
673 | sizeof c -> remote_addr.sin_addr); | |
674 | c -> remote_addr.sin_family = AF_INET; | |
675 | c -> remote_addr.sin_port = | |
676 | htons (c -> connect_list -> addresses [c -> cptr].port); | |
677 | #if defined (HAVE_SA_LEN) | |
678 | c -> remote_addr.sin_len = sizeof c -> remote_addr; | |
679 | #endif | |
680 | memset (&c -> remote_addr.sin_zero, 0, | |
681 | sizeof c -> remote_addr.sin_zero); | |
682 | ++c -> cptr; | |
683 | ||
d86ec998 TL |
684 | error = connect (c -> socket, |
685 | (struct sockaddr *)&c -> remote_addr, | |
686 | sizeof c -> remote_addr); | |
687 | if (error < 0) { | |
688 | error = errno; | |
689 | if (error != EINPROGRESS) { | |
fc24e951 | 690 | omapi_disconnect (h, 1); |
67a291cf TL |
691 | switch (error) { |
692 | case ECONNREFUSED: | |
693 | status = ISC_R_CONNREFUSED; | |
694 | break; | |
695 | case ENETUNREACH: | |
696 | status = ISC_R_NETUNREACH; | |
697 | break; | |
698 | default: | |
aaa98d8c | 699 | status = uerr2isc (error); |
67a291cf TL |
700 | break; |
701 | } | |
702 | return status; | |
fc24e951 TL |
703 | } |
704 | c -> state = omapi_connection_connecting; | |
98bf1607 | 705 | return DHCP_R_INCOMPLETE; |
fc24e951 TL |
706 | } |
707 | c -> state = omapi_connection_connected; | |
708 | } | |
709 | ||
710 | /* I don't know why this would fail, so I'm tempted not to test | |
711 | the return value. */ | |
712 | sl = sizeof (c -> local_addr); | |
713 | if (getsockname (c -> socket, | |
714 | (struct sockaddr *)&c -> local_addr, &sl) < 0) { | |
715 | } | |
716 | ||
0493fdca SR |
717 | /* Reregister with the I/O object. If we don't already have an |
718 | I/O object this turns into a register call, otherwise we simply | |
719 | modify the pointers in the I/O object. */ | |
720 | ||
721 | status = omapi_reregister_io_object (h, | |
722 | omapi_connection_readfd, | |
723 | omapi_connection_writefd, | |
724 | omapi_connection_reader, | |
725 | omapi_connection_writer, | |
726 | omapi_connection_reaper); | |
fc24e951 TL |
727 | |
728 | if (status != ISC_R_SUCCESS) { | |
729 | omapi_disconnect (h, 1); | |
730 | return status; | |
731 | } | |
732 | ||
733 | omapi_signal_in (h, "connect"); | |
734 | omapi_addr_list_dereference (&c -> connect_list, MDL); | |
8fa0112d | 735 | return ISC_R_INPROGRESS; |
fc24e951 TL |
736 | } |
737 | ||
61b844bf TL |
738 | /* Reaper function for connection - if the connection is completely closed, |
739 | reap it. If it's in the disconnecting state, there were bytes left | |
740 | to write when the user closed it, so if there are now no bytes left to | |
741 | write, we can close it. */ | |
742 | isc_result_t omapi_connection_reaper (omapi_object_t *h) | |
743 | { | |
744 | omapi_connection_object_t *c; | |
745 | ||
746 | if (h -> type != omapi_type_connection) | |
98bf1607 | 747 | return DHCP_R_INVALIDARG; |
61b844bf TL |
748 | |
749 | c = (omapi_connection_object_t *)h; | |
750 | if (c -> state == omapi_connection_disconnecting && | |
e11a162f DN |
751 | c -> out_bytes == 0) { |
752 | #ifdef DEBUG_PROTOCOL | |
753 | log_debug ("omapi_connection_reaper(): disconnect"); | |
754 | #endif | |
61b844bf | 755 | omapi_disconnect (h, 1); |
e11a162f DN |
756 | } |
757 | if (c -> state == omapi_connection_closed) { | |
758 | #ifdef DEBUG_PROTOCOL | |
759 | log_debug ("omapi_connection_reaper(): closed"); | |
760 | #endif | |
61b844bf | 761 | return ISC_R_NOTCONNECTED; |
e11a162f | 762 | } |
61b844bf TL |
763 | return ISC_R_SUCCESS; |
764 | } | |
765 | ||
98bf1607 | 766 | static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) { |
49146f3c DN |
767 | omapi_value_t *name = (omapi_value_t *)0; |
768 | omapi_value_t *algorithm = (omapi_value_t *)0; | |
769 | omapi_value_t *key = (omapi_value_t *)0; | |
98311e4b | 770 | char *name_str = NULL; |
49146f3c DN |
771 | isc_result_t status = ISC_R_SUCCESS; |
772 | ||
773 | if (status == ISC_R_SUCCESS) | |
774 | status = omapi_get_value_str | |
775 | (a, (omapi_object_t *)0, "name", &name); | |
776 | ||
777 | if (status == ISC_R_SUCCESS) | |
778 | status = omapi_get_value_str | |
779 | (a, (omapi_object_t *)0, "algorithm", &algorithm); | |
780 | ||
781 | if (status == ISC_R_SUCCESS) | |
782 | status = omapi_get_value_str | |
783 | (a, (omapi_object_t *)0, "key", &key); | |
784 | ||
785 | if (status == ISC_R_SUCCESS) { | |
98bf1607 SR |
786 | if ((algorithm->value->type != omapi_datatype_data && |
787 | algorithm->value->type != omapi_datatype_string) || | |
788 | strncasecmp((char *)algorithm->value->u.buffer.value, | |
789 | NS_TSIG_ALG_HMAC_MD5 ".", | |
790 | algorithm->value->u.buffer.len) != 0) { | |
791 | status = DHCP_R_INVALIDARG; | |
49146f3c DN |
792 | } |
793 | } | |
794 | ||
795 | if (status == ISC_R_SUCCESS) { | |
796 | name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL); | |
797 | if (!name_str) | |
798 | status = ISC_R_NOMEMORY; | |
799 | } | |
800 | ||
801 | if (status == ISC_R_SUCCESS) { | |
802 | memcpy (name_str, | |
803 | name -> value -> u.buffer.value, | |
804 | name -> value -> u.buffer.len); | |
805 | name_str [name -> value -> u.buffer.len] = 0; | |
806 | ||
98bf1607 SR |
807 | status = isclib_make_dst_key(name_str, |
808 | DHCP_HMAC_MD5_NAME, | |
809 | key->value->u.buffer.value, | |
810 | key->value->u.buffer.len, | |
811 | dst_key); | |
812 | ||
813 | if (*dst_key == NULL) | |
49146f3c DN |
814 | status = ISC_R_NOMEMORY; |
815 | } | |
816 | ||
817 | if (name_str) | |
818 | dfree (name_str, MDL); | |
819 | if (key) | |
820 | omapi_value_dereference (&key, MDL); | |
821 | if (algorithm) | |
822 | omapi_value_dereference (&algorithm, MDL); | |
823 | if (name) | |
824 | omapi_value_dereference (&name, MDL); | |
825 | ||
826 | return status; | |
827 | } | |
828 | ||
829 | isc_result_t omapi_connection_sign_data (int mode, | |
98bf1607 | 830 | dst_key_t *key, |
49146f3c | 831 | void **context, |
4b63c26e | 832 | const unsigned char *data, |
49146f3c DN |
833 | const unsigned len, |
834 | omapi_typed_data_t **result) | |
835 | { | |
836 | omapi_typed_data_t *td = (omapi_typed_data_t *)0; | |
837 | isc_result_t status; | |
98bf1607 | 838 | dst_context_t **dctx = (dst_context_t **)context; |
49146f3c | 839 | |
98bf1607 SR |
840 | /* Create the context for the dst module */ |
841 | if (mode & SIG_MODE_INIT) { | |
842 | status = dst_context_create(key, dhcp_gbl_ctx.mctx, dctx); | |
843 | if (status != ISC_R_SUCCESS) { | |
844 | return status; | |
845 | } | |
846 | } | |
847 | ||
848 | /* If we have any data add it to the context */ | |
849 | if (len != 0) { | |
850 | isc_region_t region; | |
851 | region.base = (unsigned char *)data; | |
852 | region.length = len; | |
853 | dst_context_adddata(*dctx, ®ion); | |
854 | } | |
855 | ||
856 | /* Finish the signature and clean up the context */ | |
49146f3c | 857 | if (mode & SIG_MODE_FINAL) { |
98bf1607 SR |
858 | unsigned int sigsize; |
859 | isc_buffer_t sigbuf; | |
860 | ||
861 | status = dst_key_sigsize(key, &sigsize); | |
862 | if (status != ISC_R_SUCCESS) { | |
863 | goto cleanup; | |
864 | } | |
865 | ||
49146f3c DN |
866 | status = omapi_typed_data_new (MDL, &td, |
867 | omapi_datatype_data, | |
98bf1607 SR |
868 | sigsize); |
869 | if (status != ISC_R_SUCCESS) { | |
870 | goto cleanup; | |
871 | } | |
49146f3c | 872 | |
98bf1607 SR |
873 | isc_buffer_init(&sigbuf, td->u.buffer.value, td->u.buffer.len); |
874 | status = dst_context_sign(*dctx, &sigbuf); | |
875 | if (status != ISC_R_SUCCESS) { | |
876 | goto cleanup; | |
877 | } | |
49146f3c | 878 | |
98bf1607 SR |
879 | if (result) { |
880 | omapi_typed_data_reference (result, td, MDL); | |
881 | } | |
49146f3c | 882 | |
98bf1607 SR |
883 | cleanup: |
884 | /* We are done with the context and the td. On success | |
885 | * the td is now referenced from result, on failure we | |
886 | * don't need it any more */ | |
887 | if (td) { | |
49146f3c | 888 | omapi_typed_data_dereference (&td, MDL); |
98bf1607 SR |
889 | } |
890 | dst_context_destroy(dctx); | |
891 | return status; | |
49146f3c DN |
892 | } |
893 | ||
49146f3c DN |
894 | return ISC_R_SUCCESS; |
895 | } | |
896 | ||
897 | isc_result_t omapi_connection_output_auth_length (omapi_object_t *h, | |
898 | unsigned *l) | |
899 | { | |
900 | omapi_connection_object_t *c; | |
901 | ||
98bf1607 SR |
902 | if (h->type != omapi_type_connection) |
903 | return DHCP_R_INVALIDARG; | |
49146f3c DN |
904 | c = (omapi_connection_object_t *)h; |
905 | ||
98bf1607 | 906 | if (c->out_key == NULL) |
49146f3c DN |
907 | return ISC_R_NOTFOUND; |
908 | ||
98bf1607 | 909 | return(dst_key_sigsize(c->out_key, l)); |
49146f3c DN |
910 | } |
911 | ||
61b844bf TL |
912 | isc_result_t omapi_connection_set_value (omapi_object_t *h, |
913 | omapi_object_t *id, | |
914 | omapi_data_string_t *name, | |
915 | omapi_typed_data_t *value) | |
916 | { | |
49146f3c DN |
917 | omapi_connection_object_t *c; |
918 | isc_result_t status; | |
919 | ||
61b844bf | 920 | if (h -> type != omapi_type_connection) |
98bf1607 | 921 | return DHCP_R_INVALIDARG; |
49146f3c DN |
922 | c = (omapi_connection_object_t *)h; |
923 | ||
924 | if (omapi_ds_strcmp (name, "input-authenticator") == 0) { | |
925 | if (value && value -> type != omapi_datatype_object) | |
98bf1607 | 926 | return DHCP_R_INVALIDARG; |
49146f3c DN |
927 | |
928 | if (c -> in_context) { | |
929 | omapi_connection_sign_data (SIG_MODE_FINAL, | |
930 | c -> in_key, | |
931 | &c -> in_context, | |
932 | 0, 0, | |
933 | (omapi_typed_data_t **) 0); | |
934 | } | |
935 | ||
98bf1607 SR |
936 | if (c->in_key != NULL) { |
937 | dst_key_free(&c->in_key); | |
49146f3c DN |
938 | } |
939 | ||
940 | if (value) { | |
941 | status = make_dst_key (&c -> in_key, | |
942 | value -> u.object); | |
943 | if (status != ISC_R_SUCCESS) | |
944 | return status; | |
945 | } | |
946 | ||
947 | return ISC_R_SUCCESS; | |
948 | } | |
949 | else if (omapi_ds_strcmp (name, "output-authenticator") == 0) { | |
950 | if (value && value -> type != omapi_datatype_object) | |
98bf1607 | 951 | return DHCP_R_INVALIDARG; |
49146f3c DN |
952 | |
953 | if (c -> out_context) { | |
954 | omapi_connection_sign_data (SIG_MODE_FINAL, | |
955 | c -> out_key, | |
956 | &c -> out_context, | |
957 | 0, 0, | |
958 | (omapi_typed_data_t **) 0); | |
959 | } | |
960 | ||
98bf1607 SR |
961 | if (c->out_key != NULL) { |
962 | dst_key_free(&c->out_key); | |
49146f3c DN |
963 | } |
964 | ||
965 | if (value) { | |
966 | status = make_dst_key (&c -> out_key, | |
967 | value -> u.object); | |
968 | if (status != ISC_R_SUCCESS) | |
969 | return status; | |
970 | } | |
971 | ||
972 | return ISC_R_SUCCESS; | |
973 | } | |
61b844bf TL |
974 | |
975 | if (h -> inner && h -> inner -> type -> set_value) | |
976 | return (*(h -> inner -> type -> set_value)) | |
977 | (h -> inner, id, name, value); | |
978 | return ISC_R_NOTFOUND; | |
979 | } | |
980 | ||
981 | isc_result_t omapi_connection_get_value (omapi_object_t *h, | |
982 | omapi_object_t *id, | |
983 | omapi_data_string_t *name, | |
984 | omapi_value_t **value) | |
985 | { | |
49146f3c DN |
986 | omapi_connection_object_t *c; |
987 | omapi_typed_data_t *td = (omapi_typed_data_t *)0; | |
988 | isc_result_t status; | |
98bf1607 | 989 | unsigned int sigsize; |
49146f3c | 990 | |
61b844bf | 991 | if (h -> type != omapi_type_connection) |
98bf1607 | 992 | return DHCP_R_INVALIDARG; |
49146f3c DN |
993 | c = (omapi_connection_object_t *)h; |
994 | ||
995 | if (omapi_ds_strcmp (name, "input-signature") == 0) { | |
996 | if (!c -> in_key || !c -> in_context) | |
997 | return ISC_R_NOTFOUND; | |
998 | ||
999 | status = omapi_connection_sign_data (SIG_MODE_FINAL, | |
1000 | c -> in_key, | |
1001 | &c -> in_context, | |
1002 | 0, 0, &td); | |
1003 | if (status != ISC_R_SUCCESS) | |
1004 | return status; | |
1005 | ||
1006 | status = omapi_make_value (value, name, td, MDL); | |
1007 | omapi_typed_data_dereference (&td, MDL); | |
1008 | return status; | |
1009 | ||
1010 | } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) { | |
98bf1607 | 1011 | if (c->in_key == NULL) |
49146f3c DN |
1012 | return ISC_R_NOTFOUND; |
1013 | ||
98bf1607 SR |
1014 | status = dst_key_sigsize(c->in_key, &sigsize); |
1015 | if (status != ISC_R_SUCCESS) { | |
1016 | return(status); | |
1017 | } | |
1018 | ||
1019 | return omapi_make_int_value(value, name, sigsize, MDL); | |
49146f3c DN |
1020 | |
1021 | } else if (omapi_ds_strcmp (name, "output-signature") == 0) { | |
1022 | if (!c -> out_key || !c -> out_context) | |
1023 | return ISC_R_NOTFOUND; | |
1024 | ||
1025 | status = omapi_connection_sign_data (SIG_MODE_FINAL, | |
1026 | c -> out_key, | |
1027 | &c -> out_context, | |
1028 | 0, 0, &td); | |
1029 | if (status != ISC_R_SUCCESS) | |
1030 | return status; | |
1031 | ||
1032 | status = omapi_make_value (value, name, td, MDL); | |
1033 | omapi_typed_data_dereference (&td, MDL); | |
1034 | return status; | |
1035 | ||
1036 | } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) { | |
98bf1607 | 1037 | if (c->out_key == NULL) |
49146f3c DN |
1038 | return ISC_R_NOTFOUND; |
1039 | ||
98bf1607 SR |
1040 | |
1041 | status = dst_key_sigsize(c->out_key, &sigsize); | |
1042 | if (status != ISC_R_SUCCESS) { | |
1043 | return(status); | |
1044 | } | |
1045 | ||
1046 | return omapi_make_int_value(value, name, sigsize, MDL); | |
49146f3c | 1047 | } |
61b844bf TL |
1048 | |
1049 | if (h -> inner && h -> inner -> type -> get_value) | |
1050 | return (*(h -> inner -> type -> get_value)) | |
1051 | (h -> inner, id, name, value); | |
1052 | return ISC_R_NOTFOUND; | |
1053 | } | |
1054 | ||
4bd8800e TL |
1055 | isc_result_t omapi_connection_destroy (omapi_object_t *h, |
1056 | const char *file, int line) | |
61b844bf TL |
1057 | { |
1058 | omapi_connection_object_t *c; | |
1059 | ||
e11a162f DN |
1060 | #ifdef DEBUG_PROTOCOL |
1061 | log_debug ("omapi_connection_destroy()"); | |
1062 | #endif | |
1063 | ||
61b844bf TL |
1064 | if (h -> type != omapi_type_connection) |
1065 | return ISC_R_UNEXPECTED; | |
1066 | c = (omapi_connection_object_t *)(h); | |
1067 | if (c -> state == omapi_connection_connected) | |
1068 | omapi_disconnect (h, 1); | |
1069 | if (c -> listener) | |
20916cae | 1070 | omapi_listener_dereference (&c -> listener, file, line); |
fc24e951 TL |
1071 | if (c -> connect_list) |
1072 | omapi_addr_list_dereference (&c -> connect_list, file, line); | |
61b844bf TL |
1073 | return ISC_R_SUCCESS; |
1074 | } | |
1075 | ||
1076 | isc_result_t omapi_connection_signal_handler (omapi_object_t *h, | |
b1b7b521 | 1077 | const char *name, va_list ap) |
61b844bf TL |
1078 | { |
1079 | if (h -> type != omapi_type_connection) | |
98bf1607 | 1080 | return DHCP_R_INVALIDARG; |
e11a162f DN |
1081 | |
1082 | #ifdef DEBUG_PROTOCOL | |
1083 | log_debug ("omapi_connection_signal_handler(%s)", name); | |
1084 | #endif | |
61b844bf TL |
1085 | |
1086 | if (h -> inner && h -> inner -> type -> signal_handler) | |
1087 | return (*(h -> inner -> type -> signal_handler)) (h -> inner, | |
1088 | name, ap); | |
1089 | return ISC_R_NOTFOUND; | |
1090 | } | |
1091 | ||
1092 | /* Write all the published values associated with the object through the | |
1093 | specified connection. */ | |
1094 | ||
1095 | isc_result_t omapi_connection_stuff_values (omapi_object_t *c, | |
1096 | omapi_object_t *id, | |
1097 | omapi_object_t *m) | |
1098 | { | |
61b844bf | 1099 | if (m -> type != omapi_type_connection) |
98bf1607 | 1100 | return DHCP_R_INVALIDARG; |
61b844bf TL |
1101 | |
1102 | if (m -> inner && m -> inner -> type -> stuff_values) | |
1103 | return (*(m -> inner -> type -> stuff_values)) (c, id, | |
1104 | m -> inner); | |
1105 | return ISC_R_SUCCESS; | |
1106 | } |