]> git.ipfire.org Git - thirdparty/dhcp.git/blob - omapip/connection.c
Code cleanup to remove warnings from "gcc -Wall".
[thirdparty/dhcp.git] / omapip / connection.c
1 /* connection.c
2
3 Subroutines for dealing with connections. */
4
5 /*
6 * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1999-2003 by Internet Software Consortium
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
26 *
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
33 */
34
35 #include "dhcpd.h"
36
37 #include <omapip/omapip_p.h>
38 #include <arpa/inet.h>
39 #include <arpa/nameser.h>
40 #include <errno.h>
41
42
43 #if defined (TRACING)
44 static void trace_connect_input (trace_type_t *, unsigned, char *);
45 static void trace_connect_stop (trace_type_t *);
46 static void trace_disconnect_input (trace_type_t *, unsigned, char *);
47 static void trace_disconnect_stop (trace_type_t *);
48 trace_type_t *trace_connect;
49 trace_type_t *trace_disconnect;
50 extern omapi_array_t *trace_listeners;
51 #endif
52 static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
53
54 OMAPI_OBJECT_ALLOC (omapi_connection,
55 omapi_connection_object_t, omapi_type_connection)
56
57 isc_result_t omapi_connect (omapi_object_t *c,
58 const char *server_name,
59 unsigned port)
60 {
61 struct hostent *he;
62 unsigned i, hix;
63 omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
64 struct in_addr foo;
65 isc_result_t status;
66
67 #ifdef DEBUG_PROTOCOL
68 log_debug ("omapi_connect(%s, port=%d)", server_name, port);
69 #endif
70
71 if (!inet_aton (server_name, &foo)) {
72 /* If we didn't get a numeric address, try for a domain
73 name. It's okay for this call to block. */
74 he = gethostbyname (server_name);
75 if (!he)
76 return ISC_R_HOSTUNKNOWN;
77 for (i = 0; he -> h_addr_list [i]; i++)
78 ;
79 if (i == 0)
80 return ISC_R_HOSTUNKNOWN;
81 hix = i;
82
83 status = omapi_addr_list_new (&addrs, hix, MDL);
84 if (status != ISC_R_SUCCESS)
85 return status;
86 for (i = 0; i < hix; i++) {
87 addrs -> addresses [i].addrtype = he -> h_addrtype;
88 addrs -> addresses [i].addrlen = he -> h_length;
89 memcpy (addrs -> addresses [i].address,
90 he -> h_addr_list [i],
91 (unsigned)he -> h_length);
92 addrs -> addresses [i].port = port;
93 }
94 } else {
95 status = omapi_addr_list_new (&addrs, 1, MDL);
96 if (status != ISC_R_SUCCESS)
97 return status;
98 addrs -> addresses [0].addrtype = AF_INET;
99 addrs -> addresses [0].addrlen = sizeof foo;
100 memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
101 addrs -> addresses [0].port = port;
102 hix = 1;
103 }
104 status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
105 omapi_addr_list_dereference (&addrs, MDL);
106 return status;
107 }
108
109 isc_result_t omapi_connect_list (omapi_object_t *c,
110 omapi_addr_list_t *remote_addrs,
111 omapi_addr_t *local_addr)
112 {
113 isc_result_t status;
114 omapi_connection_object_t *obj;
115 int flag;
116 struct sockaddr_in local_sin;
117
118 obj = (omapi_connection_object_t *)0;
119 status = omapi_connection_allocate (&obj, MDL);
120 if (status != ISC_R_SUCCESS)
121 return status;
122
123 status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
124 MDL);
125 if (status != ISC_R_SUCCESS) {
126 omapi_connection_dereference (&obj, MDL);
127 return status;
128 }
129 status = omapi_object_reference (&obj -> inner, c, MDL);
130 if (status != ISC_R_SUCCESS) {
131 omapi_connection_dereference (&obj, MDL);
132 return status;
133 }
134
135 /* Store the address list on the object. */
136 omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
137 obj -> cptr = 0;
138 obj -> state = omapi_connection_unconnected;
139
140 #if defined (TRACING)
141 /* If we're playing back, don't actually try to connect - just leave
142 the object available for a subsequent connect or disconnect. */
143 if (!trace_playback ()) {
144 #endif
145 /* Create a socket on which to communicate. */
146 obj -> socket =
147 socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
148 if (obj -> socket < 0) {
149 omapi_connection_dereference (&obj, MDL);
150 if (errno == EMFILE || errno == ENFILE
151 || errno == ENOBUFS)
152 return ISC_R_NORESOURCES;
153 return ISC_R_UNEXPECTED;
154 }
155
156 /* Set up the local address, if any. */
157 if (local_addr) {
158 /* Only do TCPv4 so far. */
159 if (local_addr -> addrtype != AF_INET) {
160 omapi_connection_dereference (&obj, MDL);
161 return ISC_R_INVALIDARG;
162 }
163 local_sin.sin_port = htons (local_addr -> port);
164 memcpy (&local_sin.sin_addr,
165 local_addr -> address,
166 local_addr -> addrlen);
167 #if defined (HAVE_SA_LEN)
168 local_sin.sin_len = sizeof local_addr;
169 #endif
170 local_sin.sin_family = AF_INET;
171 memset (&local_sin.sin_zero, 0,
172 sizeof local_sin.sin_zero);
173
174 if (bind (obj -> socket, (struct sockaddr *)&local_sin,
175 sizeof local_sin) < 0) {
176 omapi_object_dereference ((omapi_object_t **)
177 &obj, MDL);
178 if (errno == EADDRINUSE)
179 return ISC_R_ADDRINUSE;
180 if (errno == EADDRNOTAVAIL)
181 return ISC_R_ADDRNOTAVAIL;
182 if (errno == EACCES)
183 return ISC_R_NOPERM;
184 return ISC_R_UNEXPECTED;
185 }
186 obj -> local_addr = local_sin;
187 }
188
189 #if defined(F_SETFD)
190 if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
191 close (obj -> socket);
192 omapi_connection_dereference (&obj, MDL);
193 return ISC_R_UNEXPECTED;
194 }
195 #endif
196
197 /* Set the SO_REUSEADDR flag (this should not fail). */
198 flag = 1;
199 if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
200 (char *)&flag, sizeof flag) < 0) {
201 omapi_connection_dereference (&obj, MDL);
202 return ISC_R_UNEXPECTED;
203 }
204
205 /* Set the file to nonblocking mode. */
206 if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
207 omapi_connection_dereference (&obj, MDL);
208 return ISC_R_UNEXPECTED;
209 }
210
211 status = (omapi_register_io_object
212 ((omapi_object_t *)obj,
213 0, omapi_connection_writefd,
214 0, omapi_connection_connect,
215 omapi_connection_reaper));
216 if (status != ISC_R_SUCCESS)
217 goto out;
218 status = omapi_connection_connect_internal ((omapi_object_t *)
219 obj);
220 #if defined (TRACING)
221 }
222 omapi_connection_register (obj, MDL);
223 #endif
224
225 out:
226 omapi_connection_dereference (&obj, MDL);
227 return status;
228 }
229
230 #if defined (TRACING)
231 omapi_array_t *omapi_connections;
232
233 OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t)
234
235 void omapi_connection_trace_setup (void) {
236 trace_connect = trace_type_register ("connect", (void *)0,
237 trace_connect_input,
238 trace_connect_stop, MDL);
239 trace_disconnect = trace_type_register ("disconnect", (void *)0,
240 trace_disconnect_input,
241 trace_disconnect_stop, MDL);
242 }
243
244 void omapi_connection_register (omapi_connection_object_t *obj,
245 const char *file, int line)
246 {
247 isc_result_t status;
248 trace_iov_t iov [6];
249 int iov_count = 0;
250 int32_t connect_index, listener_index;
251 static int32_t index;
252
253 if (!omapi_connections) {
254 status = omapi_connection_array_allocate (&omapi_connections,
255 file, line);
256 if (status != ISC_R_SUCCESS)
257 return;
258 }
259
260 status = omapi_connection_array_extend (omapi_connections, obj,
261 (int *)0, file, line);
262 if (status != ISC_R_SUCCESS) {
263 obj -> index = -1;
264 return;
265 }
266
267 #if defined (TRACING)
268 if (trace_record ()) {
269 /* Connection registration packet:
270
271 int32_t index
272 int32_t listener_index [-1 means no listener]
273 u_int16_t remote_port
274 u_int16_t local_port
275 u_int32_t remote_addr
276 u_int32_t local_addr */
277
278 connect_index = htonl (index);
279 index++;
280 if (obj -> listener)
281 listener_index = htonl (obj -> listener -> index);
282 else
283 listener_index = htonl (-1);
284 iov [iov_count].buf = (char *)&connect_index;
285 iov [iov_count++].len = sizeof connect_index;
286 iov [iov_count].buf = (char *)&listener_index;
287 iov [iov_count++].len = sizeof listener_index;
288 iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
289 iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
290 iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
291 iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
292 iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
293 iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
294 iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
295 iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
296
297 status = trace_write_packet_iov (trace_connect,
298 iov_count, iov, file, line);
299 }
300 #endif
301 }
302
303 static void trace_connect_input (trace_type_t *ttype,
304 unsigned length, char *buf)
305 {
306 struct sockaddr_in remote, local;
307 int32_t connect_index, listener_index;
308 char *s = buf;
309 omapi_connection_object_t *obj;
310 isc_result_t status;
311 int i;
312
313 if (length != ((sizeof connect_index) +
314 (sizeof remote.sin_port) +
315 (sizeof remote.sin_addr)) * 2) {
316 log_error ("Trace connect: invalid length %d", length);
317 return;
318 }
319
320 memset (&remote, 0, sizeof remote);
321 memset (&local, 0, sizeof local);
322 memcpy (&connect_index, s, sizeof connect_index);
323 s += sizeof connect_index;
324 memcpy (&listener_index, s, sizeof listener_index);
325 s += sizeof listener_index;
326 memcpy (&remote.sin_port, s, sizeof remote.sin_port);
327 s += sizeof remote.sin_port;
328 memcpy (&local.sin_port, s, sizeof local.sin_port);
329 s += sizeof local.sin_port;
330 memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
331 s += sizeof remote.sin_addr;
332 memcpy (&local.sin_addr, s, sizeof local.sin_addr);
333 s += sizeof local.sin_addr;
334
335 connect_index = ntohl (connect_index);
336 listener_index = ntohl (listener_index);
337
338 /* If this was a connect to a listener, then we just slap together
339 a new connection. */
340 if (listener_index != -1) {
341 omapi_listener_object_t *listener;
342 listener = (omapi_listener_object_t *)0;
343 omapi_array_foreach_begin (trace_listeners,
344 omapi_listener_object_t, lp) {
345 if (lp -> address.sin_port == local.sin_port) {
346 omapi_listener_reference (&listener, lp, MDL);
347 omapi_listener_dereference (&lp, MDL);
348 break;
349 }
350 } omapi_array_foreach_end (trace_listeners,
351 omapi_listener_object_t, lp);
352 if (!listener) {
353 log_error ("%s%ld, addr %s, port %d",
354 "Spurious traced listener connect - index ",
355 (long int)listener_index,
356 inet_ntoa (local.sin_addr),
357 ntohs (local.sin_port));
358 return;
359 }
360 obj = (omapi_connection_object_t *)0;
361 status = omapi_listener_connect (&obj, listener, -1, &remote);
362 if (status != ISC_R_SUCCESS) {
363 log_error ("traced listener connect: %s",
364 isc_result_totext (status));
365 }
366 if (obj)
367 omapi_connection_dereference (&obj, MDL);
368 omapi_listener_dereference (&listener, MDL);
369 return;
370 }
371
372 /* Find the matching connect object, if there is one. */
373 omapi_array_foreach_begin (omapi_connections,
374 omapi_connection_object_t, lp) {
375 for (i = 0; (lp -> connect_list &&
376 i < lp -> connect_list -> count); i++) {
377 if (!memcmp (&remote.sin_addr,
378 &lp -> connect_list -> addresses [i].address,
379 sizeof remote.sin_addr) &&
380 (ntohs (remote.sin_port) ==
381 lp -> connect_list -> addresses [i].port))
382 lp -> state = omapi_connection_connected;
383 lp -> remote_addr = remote;
384 lp -> remote_addr.sin_family = AF_INET;
385 omapi_addr_list_dereference (&lp -> connect_list, MDL);
386 lp -> index = connect_index;
387 status = omapi_signal_in ((omapi_object_t *)lp,
388 "connect");
389 omapi_connection_dereference (&lp, MDL);
390 return;
391 }
392 } omapi_array_foreach_end (omapi_connections,
393 omapi_connection_object_t, lp);
394
395 log_error ("Spurious traced connect - index %ld, addr %s, port %d",
396 (long int)connect_index, inet_ntoa (remote.sin_addr),
397 ntohs (remote.sin_port));
398 return;
399 }
400
401 static void trace_connect_stop (trace_type_t *ttype) { }
402
403 static void trace_disconnect_input (trace_type_t *ttype,
404 unsigned length, char *buf)
405 {
406 int32_t *index;
407 if (length != sizeof *index) {
408 log_error ("trace disconnect: wrong length %d", length);
409 return;
410 }
411
412 index = (int32_t *)buf;
413
414 omapi_array_foreach_begin (omapi_connections,
415 omapi_connection_object_t, lp) {
416 if (lp -> index == ntohl (*index)) {
417 omapi_disconnect ((omapi_object_t *)lp, 1);
418 omapi_connection_dereference (&lp, MDL);
419 return;
420 }
421 } omapi_array_foreach_end (omapi_connections,
422 omapi_connection_object_t, lp);
423
424 log_error ("trace disconnect: no connection matching index %ld",
425 (long int)ntohl (*index));
426 }
427
428 static void trace_disconnect_stop (trace_type_t *ttype) { }
429 #endif
430
431 /* Disconnect a connection object from the remote end. If force is nonzero,
432 close the connection immediately. Otherwise, shut down the receiving end
433 but allow any unsent data to be sent before actually closing the socket. */
434
435 isc_result_t omapi_disconnect (omapi_object_t *h,
436 int force)
437 {
438 omapi_connection_object_t *c;
439 isc_result_t status;
440
441 #ifdef DEBUG_PROTOCOL
442 log_debug ("omapi_disconnect(%s)", force ? "force" : "");
443 #endif
444
445 c = (omapi_connection_object_t *)h;
446 if (c -> type != omapi_type_connection)
447 return ISC_R_INVALIDARG;
448
449 #if defined (TRACING)
450 if (trace_record ()) {
451 int32_t index;
452
453 index = htonl (c -> index);
454 status = trace_write_packet (trace_disconnect,
455 sizeof index, (char *)&index,
456 MDL);
457 if (status != ISC_R_SUCCESS) {
458 trace_stop ();
459 log_error ("trace_write_packet: %s",
460 isc_result_totext (status));
461 }
462 }
463 if (!trace_playback ()) {
464 #endif
465 if (!force) {
466 /* If we're already disconnecting, we don't have to do
467 anything. */
468 if (c -> state == omapi_connection_disconnecting)
469 return ISC_R_SUCCESS;
470
471 /* Try to shut down the socket - this sends a FIN to
472 the remote end, so that it won't send us any more
473 data. If the shutdown succeeds, and we still
474 have bytes left to write, defer closing the socket
475 until that's done. */
476 if (!shutdown (c -> socket, SHUT_RD)) {
477 if (c -> out_bytes > 0) {
478 c -> state =
479 omapi_connection_disconnecting;
480 return ISC_R_SUCCESS;
481 }
482 }
483 }
484 close (c -> socket);
485 #if defined (TRACING)
486 }
487 #endif
488 c -> state = omapi_connection_closed;
489
490 /* Disconnect from I/O object, if any. */
491 if (h -> outer) {
492 if (h -> outer -> inner)
493 omapi_object_dereference (&h -> outer -> inner, MDL);
494 omapi_object_dereference (&h -> outer, MDL);
495 }
496
497 /* If whatever created us registered a signal handler, send it
498 a disconnect signal. */
499 omapi_signal (h, "disconnect", h);
500 return ISC_R_SUCCESS;
501 }
502
503 isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
504 {
505 omapi_connection_object_t *c;
506
507 if (h -> type != omapi_type_connection)
508 return ISC_R_INVALIDARG;
509 c = (omapi_connection_object_t *)h;
510
511 c -> bytes_needed = bytes;
512 if (c -> bytes_needed <= c -> in_bytes) {
513 return ISC_R_SUCCESS;
514 }
515 return ISC_R_NOTYET;
516 }
517
518 /* Return the socket on which the dispatcher should wait for readiness
519 to read, for a connection object. If we already have more bytes than
520 we need to do the next thing, and we have at least a single full input
521 buffer, then don't indicate that we're ready to read. */
522 int omapi_connection_readfd (omapi_object_t *h)
523 {
524 omapi_connection_object_t *c;
525 if (h -> type != omapi_type_connection)
526 return -1;
527 c = (omapi_connection_object_t *)h;
528 if (c -> state != omapi_connection_connected)
529 return -1;
530 if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
531 c -> in_bytes > c -> bytes_needed)
532 return -1;
533 return c -> socket;
534 }
535
536 /* Return the socket on which the dispatcher should wait for readiness
537 to write, for a connection object. If there are no bytes buffered
538 for writing, then don't indicate that we're ready to write. */
539 int omapi_connection_writefd (omapi_object_t *h)
540 {
541 omapi_connection_object_t *c;
542 if (h -> type != omapi_type_connection)
543 return -1;
544 c = (omapi_connection_object_t *)h;
545 if (c -> state == omapi_connection_connecting)
546 return c -> socket;
547 if (c -> out_bytes)
548 return c -> socket;
549 else
550 return -1;
551 }
552
553 isc_result_t omapi_connection_connect (omapi_object_t *h)
554 {
555 isc_result_t status;
556
557 status = omapi_connection_connect_internal (h);
558 if (status != ISC_R_SUCCESS)
559 omapi_signal (h, "status", status);
560 return ISC_R_SUCCESS;
561 }
562
563 static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
564 {
565 int error;
566 omapi_connection_object_t *c;
567 socklen_t sl;
568 isc_result_t status;
569
570 if (h -> type != omapi_type_connection)
571 return ISC_R_INVALIDARG;
572 c = (omapi_connection_object_t *)h;
573
574 if (c -> state == omapi_connection_connecting) {
575 sl = sizeof error;
576 if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
577 (char *)&error, &sl) < 0) {
578 omapi_disconnect (h, 1);
579 return ISC_R_SUCCESS;
580 }
581 if (!error)
582 c -> state = omapi_connection_connected;
583 }
584 if (c -> state == omapi_connection_connecting ||
585 c -> state == omapi_connection_unconnected) {
586 if (c -> cptr >= c -> connect_list -> count) {
587 switch (error) {
588 case ECONNREFUSED:
589 status = ISC_R_CONNREFUSED;
590 break;
591 case ENETUNREACH:
592 status = ISC_R_NETUNREACH;
593 break;
594 default:
595 status = uerr2isc (error);
596 break;
597 }
598 omapi_disconnect (h, 1);
599 return status;
600 }
601
602 if (c -> connect_list -> addresses [c -> cptr].addrtype !=
603 AF_INET) {
604 omapi_disconnect (h, 1);
605 return ISC_R_INVALIDARG;
606 }
607
608 memcpy (&c -> remote_addr.sin_addr,
609 &c -> connect_list -> addresses [c -> cptr].address,
610 sizeof c -> remote_addr.sin_addr);
611 c -> remote_addr.sin_family = AF_INET;
612 c -> remote_addr.sin_port =
613 htons (c -> connect_list -> addresses [c -> cptr].port);
614 #if defined (HAVE_SA_LEN)
615 c -> remote_addr.sin_len = sizeof c -> remote_addr;
616 #endif
617 memset (&c -> remote_addr.sin_zero, 0,
618 sizeof c -> remote_addr.sin_zero);
619 ++c -> cptr;
620
621 error = connect (c -> socket,
622 (struct sockaddr *)&c -> remote_addr,
623 sizeof c -> remote_addr);
624 if (error < 0) {
625 error = errno;
626 if (error != EINPROGRESS) {
627 omapi_disconnect (h, 1);
628 switch (error) {
629 case ECONNREFUSED:
630 status = ISC_R_CONNREFUSED;
631 break;
632 case ENETUNREACH:
633 status = ISC_R_NETUNREACH;
634 break;
635 default:
636 status = uerr2isc (error);
637 break;
638 }
639 return status;
640 }
641 c -> state = omapi_connection_connecting;
642 return ISC_R_INCOMPLETE;
643 }
644 c -> state = omapi_connection_connected;
645 }
646
647 /* I don't know why this would fail, so I'm tempted not to test
648 the return value. */
649 sl = sizeof (c -> local_addr);
650 if (getsockname (c -> socket,
651 (struct sockaddr *)&c -> local_addr, &sl) < 0) {
652 }
653
654 /* Disconnect from I/O object, if any. */
655 if (h -> outer)
656 omapi_unregister_io_object (h);
657
658 status = omapi_register_io_object (h,
659 omapi_connection_readfd,
660 omapi_connection_writefd,
661 omapi_connection_reader,
662 omapi_connection_writer,
663 omapi_connection_reaper);
664
665 if (status != ISC_R_SUCCESS) {
666 omapi_disconnect (h, 1);
667 return status;
668 }
669
670 omapi_signal_in (h, "connect");
671 omapi_addr_list_dereference (&c -> connect_list, MDL);
672 return ISC_R_SUCCESS;
673 }
674
675 /* Reaper function for connection - if the connection is completely closed,
676 reap it. If it's in the disconnecting state, there were bytes left
677 to write when the user closed it, so if there are now no bytes left to
678 write, we can close it. */
679 isc_result_t omapi_connection_reaper (omapi_object_t *h)
680 {
681 omapi_connection_object_t *c;
682
683 if (h -> type != omapi_type_connection)
684 return ISC_R_INVALIDARG;
685
686 c = (omapi_connection_object_t *)h;
687 if (c -> state == omapi_connection_disconnecting &&
688 c -> out_bytes == 0) {
689 #ifdef DEBUG_PROTOCOL
690 log_debug ("omapi_connection_reaper(): disconnect");
691 #endif
692 omapi_disconnect (h, 1);
693 }
694 if (c -> state == omapi_connection_closed) {
695 #ifdef DEBUG_PROTOCOL
696 log_debug ("omapi_connection_reaper(): closed");
697 #endif
698 return ISC_R_NOTCONNECTED;
699 }
700 return ISC_R_SUCCESS;
701 }
702
703 static isc_result_t make_dst_key (DST_KEY **dst_key, omapi_object_t *a) {
704 omapi_value_t *name = (omapi_value_t *)0;
705 omapi_value_t *algorithm = (omapi_value_t *)0;
706 omapi_value_t *key = (omapi_value_t *)0;
707 int algorithm_id = UNKNOWN_KEYALG;
708 char *name_str = NULL;
709 isc_result_t status = ISC_R_SUCCESS;
710
711 if (status == ISC_R_SUCCESS)
712 status = omapi_get_value_str
713 (a, (omapi_object_t *)0, "name", &name);
714
715 if (status == ISC_R_SUCCESS)
716 status = omapi_get_value_str
717 (a, (omapi_object_t *)0, "algorithm", &algorithm);
718
719 if (status == ISC_R_SUCCESS)
720 status = omapi_get_value_str
721 (a, (omapi_object_t *)0, "key", &key);
722
723 if (status == ISC_R_SUCCESS) {
724 if ((algorithm -> value -> type == omapi_datatype_data ||
725 algorithm -> value -> type == omapi_datatype_string) &&
726 strncasecmp ((char *)algorithm -> value -> u.buffer.value,
727 NS_TSIG_ALG_HMAC_MD5 ".",
728 algorithm -> value -> u.buffer.len) == 0) {
729 algorithm_id = KEY_HMAC_MD5;
730 } else {
731 status = ISC_R_INVALIDARG;
732 }
733 }
734
735 if (status == ISC_R_SUCCESS) {
736 name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL);
737 if (!name_str)
738 status = ISC_R_NOMEMORY;
739 }
740
741 if (status == ISC_R_SUCCESS) {
742 memcpy (name_str,
743 name -> value -> u.buffer.value,
744 name -> value -> u.buffer.len);
745 name_str [name -> value -> u.buffer.len] = 0;
746
747 *dst_key = dst_buffer_to_key (name_str, algorithm_id, 0, 0,
748 key -> value -> u.buffer.value,
749 key -> value -> u.buffer.len);
750 if (!*dst_key)
751 status = ISC_R_NOMEMORY;
752 }
753
754 if (name_str)
755 dfree (name_str, MDL);
756 if (key)
757 omapi_value_dereference (&key, MDL);
758 if (algorithm)
759 omapi_value_dereference (&algorithm, MDL);
760 if (name)
761 omapi_value_dereference (&name, MDL);
762
763 return status;
764 }
765
766 isc_result_t omapi_connection_sign_data (int mode,
767 DST_KEY *key,
768 void **context,
769 const unsigned char *data,
770 const unsigned len,
771 omapi_typed_data_t **result)
772 {
773 omapi_typed_data_t *td = (omapi_typed_data_t *)0;
774 isc_result_t status;
775 int r;
776
777 if (mode & SIG_MODE_FINAL) {
778 status = omapi_typed_data_new (MDL, &td,
779 omapi_datatype_data,
780 dst_sig_size (key));
781 if (status != ISC_R_SUCCESS)
782 return status;
783 }
784
785 r = dst_sign_data (mode, key, context, data, len,
786 td ? td -> u.buffer.value : (u_char *)0,
787 td ? td -> u.buffer.len : 0);
788
789 /* dst_sign_data() really should do this for us, shouldn't it? */
790 if (mode & SIG_MODE_FINAL)
791 *context = (void *)0;
792
793 if (r < 0) {
794 if (td)
795 omapi_typed_data_dereference (&td, MDL);
796 return ISC_R_INVALIDKEY;
797 }
798
799 if (result && td) {
800 omapi_typed_data_reference (result, td, MDL);
801 }
802
803 if (td)
804 omapi_typed_data_dereference (&td, MDL);
805
806 return ISC_R_SUCCESS;
807 }
808
809 isc_result_t omapi_connection_output_auth_length (omapi_object_t *h,
810 unsigned *l)
811 {
812 omapi_connection_object_t *c;
813
814 if (h -> type != omapi_type_connection)
815 return ISC_R_INVALIDARG;
816 c = (omapi_connection_object_t *)h;
817
818 if (!c -> out_key)
819 return ISC_R_NOTFOUND;
820
821 *l = dst_sig_size (c -> out_key);
822 return ISC_R_SUCCESS;
823 }
824
825 isc_result_t omapi_connection_set_value (omapi_object_t *h,
826 omapi_object_t *id,
827 omapi_data_string_t *name,
828 omapi_typed_data_t *value)
829 {
830 omapi_connection_object_t *c;
831 isc_result_t status;
832
833 if (h -> type != omapi_type_connection)
834 return ISC_R_INVALIDARG;
835 c = (omapi_connection_object_t *)h;
836
837 if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
838 if (value && value -> type != omapi_datatype_object)
839 return ISC_R_INVALIDARG;
840
841 if (c -> in_context) {
842 omapi_connection_sign_data (SIG_MODE_FINAL,
843 c -> in_key,
844 &c -> in_context,
845 0, 0,
846 (omapi_typed_data_t **) 0);
847 }
848
849 if (c -> in_key) {
850 dst_free_key (c -> in_key);
851 c -> in_key = (DST_KEY *)0;
852 }
853
854 if (value) {
855 status = make_dst_key (&c -> in_key,
856 value -> u.object);
857 if (status != ISC_R_SUCCESS)
858 return status;
859 }
860
861 return ISC_R_SUCCESS;
862 }
863 else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
864 if (value && value -> type != omapi_datatype_object)
865 return ISC_R_INVALIDARG;
866
867 if (c -> out_context) {
868 omapi_connection_sign_data (SIG_MODE_FINAL,
869 c -> out_key,
870 &c -> out_context,
871 0, 0,
872 (omapi_typed_data_t **) 0);
873 }
874
875 if (c -> out_key) {
876 dst_free_key (c -> out_key);
877 c -> out_key = (DST_KEY *)0;
878 }
879
880 if (value) {
881 status = make_dst_key (&c -> out_key,
882 value -> u.object);
883 if (status != ISC_R_SUCCESS)
884 return status;
885 }
886
887 return ISC_R_SUCCESS;
888 }
889
890 if (h -> inner && h -> inner -> type -> set_value)
891 return (*(h -> inner -> type -> set_value))
892 (h -> inner, id, name, value);
893 return ISC_R_NOTFOUND;
894 }
895
896 isc_result_t omapi_connection_get_value (omapi_object_t *h,
897 omapi_object_t *id,
898 omapi_data_string_t *name,
899 omapi_value_t **value)
900 {
901 omapi_connection_object_t *c;
902 omapi_typed_data_t *td = (omapi_typed_data_t *)0;
903 isc_result_t status;
904
905 if (h -> type != omapi_type_connection)
906 return ISC_R_INVALIDARG;
907 c = (omapi_connection_object_t *)h;
908
909 if (omapi_ds_strcmp (name, "input-signature") == 0) {
910 if (!c -> in_key || !c -> in_context)
911 return ISC_R_NOTFOUND;
912
913 status = omapi_connection_sign_data (SIG_MODE_FINAL,
914 c -> in_key,
915 &c -> in_context,
916 0, 0, &td);
917 if (status != ISC_R_SUCCESS)
918 return status;
919
920 status = omapi_make_value (value, name, td, MDL);
921 omapi_typed_data_dereference (&td, MDL);
922 return status;
923
924 } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
925 if (!c -> in_key)
926 return ISC_R_NOTFOUND;
927
928 return omapi_make_int_value (value, name,
929 dst_sig_size (c -> in_key), MDL);
930
931 } else if (omapi_ds_strcmp (name, "output-signature") == 0) {
932 if (!c -> out_key || !c -> out_context)
933 return ISC_R_NOTFOUND;
934
935 status = omapi_connection_sign_data (SIG_MODE_FINAL,
936 c -> out_key,
937 &c -> out_context,
938 0, 0, &td);
939 if (status != ISC_R_SUCCESS)
940 return status;
941
942 status = omapi_make_value (value, name, td, MDL);
943 omapi_typed_data_dereference (&td, MDL);
944 return status;
945
946 } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
947 if (!c -> out_key)
948 return ISC_R_NOTFOUND;
949
950 return omapi_make_int_value (value, name,
951 dst_sig_size (c -> out_key), MDL);
952 }
953
954 if (h -> inner && h -> inner -> type -> get_value)
955 return (*(h -> inner -> type -> get_value))
956 (h -> inner, id, name, value);
957 return ISC_R_NOTFOUND;
958 }
959
960 isc_result_t omapi_connection_destroy (omapi_object_t *h,
961 const char *file, int line)
962 {
963 omapi_connection_object_t *c;
964
965 #ifdef DEBUG_PROTOCOL
966 log_debug ("omapi_connection_destroy()");
967 #endif
968
969 if (h -> type != omapi_type_connection)
970 return ISC_R_UNEXPECTED;
971 c = (omapi_connection_object_t *)(h);
972 if (c -> state == omapi_connection_connected)
973 omapi_disconnect (h, 1);
974 if (c -> listener)
975 omapi_listener_dereference (&c -> listener, file, line);
976 if (c -> connect_list)
977 omapi_addr_list_dereference (&c -> connect_list, file, line);
978 return ISC_R_SUCCESS;
979 }
980
981 isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
982 const char *name, va_list ap)
983 {
984 if (h -> type != omapi_type_connection)
985 return ISC_R_INVALIDARG;
986
987 #ifdef DEBUG_PROTOCOL
988 log_debug ("omapi_connection_signal_handler(%s)", name);
989 #endif
990
991 if (h -> inner && h -> inner -> type -> signal_handler)
992 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
993 name, ap);
994 return ISC_R_NOTFOUND;
995 }
996
997 /* Write all the published values associated with the object through the
998 specified connection. */
999
1000 isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
1001 omapi_object_t *id,
1002 omapi_object_t *m)
1003 {
1004 if (m -> type != omapi_type_connection)
1005 return ISC_R_INVALIDARG;
1006
1007 if (m -> inner && m -> inner -> type -> stuff_values)
1008 return (*(m -> inner -> type -> stuff_values)) (c, id,
1009 m -> inner);
1010 return ISC_R_SUCCESS;
1011 }