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