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