3 Subroutines for dealing with connections. */
6 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1999-2003 by Internet Software Consortium
9 * This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
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.
21 * Internet Systems Consortium, Inc.
23 * Newmarket, NH 03857 USA
25 * https://www.isc.org/
31 #include <omapip/omapip_p.h>
32 #include <arpa/inet.h>
33 #include <arpa/nameser.h>
37 static void trace_connect_input (trace_type_t
*, unsigned, char *);
38 static void trace_connect_stop (trace_type_t
*);
39 static void trace_disconnect_input (trace_type_t
*, unsigned, char *);
40 static void trace_disconnect_stop (trace_type_t
*);
41 trace_type_t
*trace_connect
;
42 trace_type_t
*trace_disconnect
;
43 extern omapi_array_t
*trace_listeners
;
45 static isc_result_t
omapi_connection_connect_internal (omapi_object_t
*);
47 static isc_result_t
ctring_from_attribute(omapi_object_t
*obj
, char *attr_name
,
50 OMAPI_OBJECT_ALLOC (omapi_connection
,
51 omapi_connection_object_t
, omapi_type_connection
)
53 isc_result_t
omapi_connect (omapi_object_t
*c
,
54 const char *server_name
,
59 omapi_addr_list_t
*addrs
= (omapi_addr_list_t
*)0;
64 log_debug ("omapi_connect(%s, port=%d)", server_name
, port
);
67 if (!inet_aton (server_name
, &foo
)) {
68 /* If we didn't get a numeric address, try for a domain
69 name. It's okay for this call to block. */
70 he
= gethostbyname (server_name
);
72 return DHCP_R_HOSTUNKNOWN
;
73 for (i
= 0; he
-> h_addr_list
[i
]; i
++)
76 return DHCP_R_HOSTUNKNOWN
;
79 status
= omapi_addr_list_new (&addrs
, hix
, MDL
);
80 if (status
!= ISC_R_SUCCESS
)
82 for (i
= 0; i
< hix
; i
++) {
83 addrs
-> addresses
[i
].addrtype
= he
-> h_addrtype
;
84 addrs
-> addresses
[i
].addrlen
= he
-> h_length
;
85 memcpy (addrs
-> addresses
[i
].address
,
86 he
-> h_addr_list
[i
],
87 (unsigned)he
-> h_length
);
88 addrs
-> addresses
[i
].port
= port
;
91 status
= omapi_addr_list_new (&addrs
, 1, MDL
);
92 if (status
!= ISC_R_SUCCESS
)
94 addrs
-> addresses
[0].addrtype
= AF_INET
;
95 addrs
-> addresses
[0].addrlen
= sizeof foo
;
96 memcpy (addrs
-> addresses
[0].address
, &foo
, sizeof foo
);
97 addrs
-> addresses
[0].port
= port
;
99 status
= omapi_connect_list (c
, addrs
, (omapi_addr_t
*)0);
100 omapi_addr_list_dereference (&addrs
, MDL
);
104 isc_result_t
omapi_connect_list (omapi_object_t
*c
,
105 omapi_addr_list_t
*remote_addrs
,
106 omapi_addr_t
*local_addr
)
109 omapi_connection_object_t
*obj
;
111 struct sockaddr_in local_sin
;
113 obj
= (omapi_connection_object_t
*)0;
114 status
= omapi_connection_allocate (&obj
, MDL
);
115 if (status
!= ISC_R_SUCCESS
)
118 status
= omapi_object_reference (&c
-> outer
, (omapi_object_t
*)obj
,
120 if (status
!= ISC_R_SUCCESS
) {
121 omapi_connection_dereference (&obj
, MDL
);
124 status
= omapi_object_reference (&obj
-> inner
, c
, MDL
);
125 if (status
!= ISC_R_SUCCESS
) {
126 omapi_connection_dereference (&obj
, MDL
);
130 /* Store the address list on the object. */
131 omapi_addr_list_reference (&obj
-> connect_list
, remote_addrs
, MDL
);
133 obj
-> state
= omapi_connection_unconnected
;
135 #if defined (TRACING)
136 /* If we're playing back, don't actually try to connect - just leave
137 the object available for a subsequent connect or disconnect. */
138 if (!trace_playback ()) {
140 /* Create a socket on which to communicate. */
142 socket (PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
143 if (obj
-> socket
< 0) {
144 omapi_connection_dereference (&obj
, MDL
);
145 if (errno
== EMFILE
|| errno
== ENFILE
147 return ISC_R_NORESOURCES
;
148 return ISC_R_UNEXPECTED
;
151 /* Set up the local address, if any. */
153 /* Only do TCPv4 so far. */
154 if (local_addr
-> addrtype
!= AF_INET
) {
156 omapi_connection_dereference (&obj
, MDL
);
157 return DHCP_R_INVALIDARG
;
159 local_sin
.sin_port
= htons (local_addr
-> port
);
160 memcpy (&local_sin
.sin_addr
,
161 local_addr
-> address
,
162 local_addr
-> addrlen
);
163 #if defined (HAVE_SA_LEN)
164 local_sin
.sin_len
= sizeof local_addr
;
166 local_sin
.sin_family
= AF_INET
;
167 memset (&local_sin
.sin_zero
, 0,
168 sizeof local_sin
.sin_zero
);
170 if (bind (obj
-> socket
, (struct sockaddr
*)&local_sin
,
171 sizeof local_sin
) < 0) {
172 omapi_connection_object_t
**objp
= &obj
;
173 omapi_object_t
**o
= (omapi_object_t
**)objp
;
175 omapi_object_dereference(o
, MDL
);
176 if (errno
== EADDRINUSE
)
177 return ISC_R_ADDRINUSE
;
178 if (errno
== EADDRNOTAVAIL
)
179 return ISC_R_ADDRNOTAVAIL
;
182 return ISC_R_UNEXPECTED
;
184 obj
-> local_addr
= local_sin
;
188 if (fcntl (obj
-> socket
, F_SETFD
, 1) < 0) {
189 close (obj
-> socket
);
190 omapi_connection_dereference (&obj
, MDL
);
191 return ISC_R_UNEXPECTED
;
195 /* Set the SO_REUSEADDR flag (this should not fail). */
197 if (setsockopt (obj
-> socket
, SOL_SOCKET
, SO_REUSEADDR
,
198 (char *)&flag
, sizeof flag
) < 0) {
199 omapi_connection_dereference (&obj
, MDL
);
200 return ISC_R_UNEXPECTED
;
203 /* Set the file to nonblocking mode. */
204 if (fcntl (obj
-> socket
, F_SETFL
, O_NONBLOCK
) < 0) {
205 omapi_connection_dereference (&obj
, MDL
);
206 return ISC_R_UNEXPECTED
;
211 * If available stop the OS from killing our
212 * program on a SIGPIPE failure
215 if (setsockopt(obj
->socket
, SOL_SOCKET
, SO_NOSIGPIPE
,
216 (char *)&flag
, sizeof(flag
)) < 0) {
217 omapi_connection_dereference (&obj
, MDL
);
218 return ISC_R_UNEXPECTED
;
222 status
= (omapi_register_io_object
223 ((omapi_object_t
*)obj
,
224 0, omapi_connection_writefd
,
225 0, omapi_connection_connect
,
226 omapi_connection_reaper
));
227 if (status
!= ISC_R_SUCCESS
)
229 status
= omapi_connection_connect_internal ((omapi_object_t
*)
232 * inprogress is the same as success but used
233 * to indicate to the dispatch code that we should
234 * mark the socket as requiring more attention.
235 * Routines calling this function should handle
238 if (status
== ISC_R_INPROGRESS
) {
239 status
= ISC_R_SUCCESS
;
241 #if defined (TRACING)
243 omapi_connection_register (obj
, MDL
);
247 omapi_connection_dereference (&obj
, MDL
);
251 #if defined (TRACING)
252 omapi_array_t
*omapi_connections
;
254 OMAPI_ARRAY_TYPE(omapi_connection
, omapi_connection_object_t
)
256 void omapi_connection_trace_setup (void) {
257 trace_connect
= trace_type_register ("connect", (void *)0,
259 trace_connect_stop
, MDL
);
260 trace_disconnect
= trace_type_register ("disconnect", (void *)0,
261 trace_disconnect_input
,
262 trace_disconnect_stop
, MDL
);
265 void omapi_connection_register (omapi_connection_object_t
*obj
,
266 const char *file
, int line
)
271 int32_t connect_index
, listener_index
;
272 static int32_t index
;
274 if (!omapi_connections
) {
275 status
= omapi_connection_array_allocate (&omapi_connections
,
277 if (status
!= ISC_R_SUCCESS
)
281 status
= omapi_connection_array_extend (omapi_connections
, obj
,
282 (int *)0, file
, line
);
283 if (status
!= ISC_R_SUCCESS
) {
288 #if defined (TRACING)
289 if (trace_record ()) {
290 /* Connection registration packet:
293 int32_t listener_index [-1 means no listener]
294 u_int16_t remote_port
296 u_int32_t remote_addr
297 u_int32_t local_addr */
299 connect_index
= htonl (index
);
302 listener_index
= htonl (obj
-> listener
-> index
);
304 listener_index
= htonl (-1);
305 iov
[iov_count
].buf
= (char *)&connect_index
;
306 iov
[iov_count
++].len
= sizeof connect_index
;
307 iov
[iov_count
].buf
= (char *)&listener_index
;
308 iov
[iov_count
++].len
= sizeof listener_index
;
309 iov
[iov_count
].buf
= (char *)&obj
-> remote_addr
.sin_port
;
310 iov
[iov_count
++].len
= sizeof obj
-> remote_addr
.sin_port
;
311 iov
[iov_count
].buf
= (char *)&obj
-> local_addr
.sin_port
;
312 iov
[iov_count
++].len
= sizeof obj
-> local_addr
.sin_port
;
313 iov
[iov_count
].buf
= (char *)&obj
-> remote_addr
.sin_addr
;
314 iov
[iov_count
++].len
= sizeof obj
-> remote_addr
.sin_addr
;
315 iov
[iov_count
].buf
= (char *)&obj
-> local_addr
.sin_addr
;
316 iov
[iov_count
++].len
= sizeof obj
-> local_addr
.sin_addr
;
318 status
= trace_write_packet_iov (trace_connect
,
319 iov_count
, iov
, file
, line
);
324 static void trace_connect_input (trace_type_t
*ttype
,
325 unsigned length
, char *buf
)
327 struct sockaddr_in remote
, local
;
328 int32_t connect_index
, listener_index
;
330 omapi_connection_object_t
*obj
;
334 if (length
!= ((sizeof connect_index
) +
335 (sizeof remote
.sin_port
) +
336 (sizeof remote
.sin_addr
)) * 2) {
337 log_error ("Trace connect: invalid length %d", length
);
341 memset (&remote
, 0, sizeof remote
);
342 memset (&local
, 0, sizeof local
);
343 memcpy (&connect_index
, s
, sizeof connect_index
);
344 s
+= sizeof connect_index
;
345 memcpy (&listener_index
, s
, sizeof listener_index
);
346 s
+= sizeof listener_index
;
347 memcpy (&remote
.sin_port
, s
, sizeof remote
.sin_port
);
348 s
+= sizeof remote
.sin_port
;
349 memcpy (&local
.sin_port
, s
, sizeof local
.sin_port
);
350 s
+= sizeof local
.sin_port
;
351 memcpy (&remote
.sin_addr
, s
, sizeof remote
.sin_addr
);
352 s
+= sizeof remote
.sin_addr
;
353 memcpy (&local
.sin_addr
, s
, sizeof local
.sin_addr
);
354 s
+= sizeof local
.sin_addr
;
357 connect_index
= ntohl (connect_index
);
358 listener_index
= ntohl (listener_index
);
360 /* If this was a connect to a listener, then we just slap together
362 if (listener_index
!= -1) {
363 omapi_listener_object_t
*listener
;
364 listener
= (omapi_listener_object_t
*)0;
365 omapi_array_foreach_begin (trace_listeners
,
366 omapi_listener_object_t
, lp
) {
367 if (lp
-> address
.sin_port
== local
.sin_port
) {
368 omapi_listener_reference (&listener
, lp
, MDL
);
369 omapi_listener_dereference (&lp
, MDL
);
372 } omapi_array_foreach_end (trace_listeners
,
373 omapi_listener_object_t
, lp
);
375 log_error ("%s%ld, addr %s, port %d",
376 "Spurious traced listener connect - index ",
377 (long int)listener_index
,
378 inet_ntoa (local
.sin_addr
),
379 ntohs (local
.sin_port
));
382 obj
= (omapi_connection_object_t
*)0;
383 status
= omapi_listener_connect (&obj
, listener
, -1, &remote
);
384 if (status
!= ISC_R_SUCCESS
) {
385 log_error ("traced listener connect: %s",
386 isc_result_totext (status
));
389 omapi_connection_dereference (&obj
, MDL
);
390 omapi_listener_dereference (&listener
, MDL
);
394 /* Find the matching connect object, if there is one. */
395 omapi_array_foreach_begin (omapi_connections
,
396 omapi_connection_object_t
, lp
) {
397 for (i
= 0; (lp
->connect_list
&&
398 i
< lp
->connect_list
->count
); i
++) {
399 if (!memcmp (&remote
.sin_addr
,
400 &lp
->connect_list
->addresses
[i
].address
,
401 sizeof remote
.sin_addr
) &&
402 (ntohs (remote
.sin_port
) ==
403 lp
->connect_list
->addresses
[i
].port
)) {
404 lp
->state
= omapi_connection_connected
;
405 lp
->remote_addr
= remote
;
406 lp
->remote_addr
.sin_family
= AF_INET
;
407 omapi_addr_list_dereference(&lp
->connect_list
, MDL
);
408 lp
->index
= connect_index
;
409 status
= omapi_signal_in((omapi_object_t
*)lp
,
411 omapi_connection_dereference (&lp
, MDL
);
415 } omapi_array_foreach_end (omapi_connections
,
416 omapi_connection_object_t
, lp
);
418 log_error ("Spurious traced connect - index %ld, addr %s, port %d",
419 (long int)connect_index
, inet_ntoa (remote
.sin_addr
),
420 ntohs (remote
.sin_port
));
424 static void trace_connect_stop (trace_type_t
*ttype
) { }
426 static void trace_disconnect_input (trace_type_t
*ttype
,
427 unsigned length
, char *buf
)
430 if (length
!= sizeof *index
) {
431 log_error ("trace disconnect: wrong length %d", length
);
435 index
= (int32_t *)buf
;
437 omapi_array_foreach_begin (omapi_connections
,
438 omapi_connection_object_t
, lp
) {
439 if (lp
-> index
== ntohl (*index
)) {
440 omapi_disconnect ((omapi_object_t
*)lp
, 1);
441 omapi_connection_dereference (&lp
, MDL
);
444 } omapi_array_foreach_end (omapi_connections
,
445 omapi_connection_object_t
, lp
);
447 log_error ("trace disconnect: no connection matching index %ld",
448 (long int)ntohl (*index
));
451 static void trace_disconnect_stop (trace_type_t
*ttype
) { }
454 /* Disconnect a connection object from the remote end. If force is nonzero,
455 close the connection immediately. Otherwise, shut down the receiving end
456 but allow any unsent data to be sent before actually closing the socket. */
458 isc_result_t
omapi_disconnect (omapi_object_t
*h
,
461 omapi_connection_object_t
*c
;
463 #ifdef DEBUG_PROTOCOL
464 log_debug ("omapi_disconnect(force=%d)", force
);
467 c
= (omapi_connection_object_t
*)h
;
468 if (c
-> type
!= omapi_type_connection
)
469 return DHCP_R_INVALIDARG
;
471 #if defined (TRACING)
472 if (trace_record ()) {
476 index
= htonl (c
-> index
);
477 status
= trace_write_packet (trace_disconnect
,
478 sizeof index
, (char *)&index
,
480 if (status
!= ISC_R_SUCCESS
) {
482 log_error ("trace_write_packet: %s",
483 isc_result_totext (status
));
486 if (!trace_playback ()) {
489 /* If we're already disconnecting, we don't have to do
491 if (c
-> state
== omapi_connection_disconnecting
)
492 return ISC_R_SUCCESS
;
494 /* Try to shut down the socket - this sends a FIN to
495 the remote end, so that it won't send us any more
496 data. If the shutdown succeeds, and we still
497 have bytes left to write, defer closing the socket
498 until that's done. */
499 if (!shutdown (c
-> socket
, SHUT_RD
)) {
500 if (c
-> out_bytes
> 0) {
502 omapi_connection_disconnecting
;
503 return ISC_R_SUCCESS
;
508 #if defined (TRACING)
511 c
-> state
= omapi_connection_closed
;
515 * Disconnecting from the I/O object seems incorrect as it doesn't
516 * cause the I/O object to be cleaned and released. Previous to
517 * using the isc socket library this wouldn't have caused a problem
518 * with the socket library we would have a reference to a closed
519 * socket. Instead we now do an unregister to properly free the
523 /* Disconnect from I/O object, if any. */
525 if (h
-> outer
-> inner
)
526 omapi_object_dereference (&h
-> outer
-> inner
, MDL
);
527 omapi_object_dereference (&h
-> outer
, MDL
);
531 omapi_unregister_io_object(h
);
535 /* If whatever created us registered a signal handler, send it
536 a disconnect signal. */
537 omapi_signal (h
, "disconnect", h
);
539 /* Disconnect from protocol object, if any. */
540 if (h
->inner
!= NULL
) {
541 if (h
->inner
->outer
!= NULL
) {
542 omapi_object_dereference(&h
->inner
->outer
, MDL
);
544 omapi_object_dereference(&h
->inner
, MDL
);
547 /* XXX: the code to free buffers should be in the dereference
548 function, but there is no special-purpose function to
549 dereference connections, so these just get leaked */
550 /* Free any buffers */
551 if (c
->inbufs
!= NULL
) {
552 omapi_buffer_dereference(&c
->inbufs
, MDL
);
555 if (c
->outbufs
!= NULL
) {
556 omapi_buffer_dereference(&c
->outbufs
, MDL
);
560 return ISC_R_SUCCESS
;
563 isc_result_t
omapi_connection_require (omapi_object_t
*h
, unsigned bytes
)
565 omapi_connection_object_t
*c
;
567 if (h
-> type
!= omapi_type_connection
)
568 return DHCP_R_INVALIDARG
;
569 c
= (omapi_connection_object_t
*)h
;
571 c
-> bytes_needed
= bytes
;
572 if (c
-> bytes_needed
<= c
-> in_bytes
) {
573 return ISC_R_SUCCESS
;
575 return DHCP_R_NOTYET
;
578 /* Return the socket on which the dispatcher should wait for readiness
579 to read, for a connection object. */
580 int omapi_connection_readfd (omapi_object_t
*h
)
582 omapi_connection_object_t
*c
;
583 if (h
-> type
!= omapi_type_connection
)
585 c
= (omapi_connection_object_t
*)h
;
586 if (c
-> state
!= omapi_connection_connected
)
592 * Return the socket on which the dispatcher should wait for readiness
593 * to write, for a connection object. When bytes are buffered we should
594 * also poke the dispatcher to tell it to start or re-start watching the
597 int omapi_connection_writefd (omapi_object_t
*h
)
599 omapi_connection_object_t
*c
;
600 if (h
-> type
!= omapi_type_connection
)
602 c
= (omapi_connection_object_t
*)h
;
606 isc_result_t
omapi_connection_connect (omapi_object_t
*h
)
611 * We use the INPROGRESS status to indicate that
612 * we want more from the socket. In this case we
613 * have now connected and are trying to write to
614 * the socket for the first time. For the signaling
615 * code this is the same as a SUCCESS so we don't
616 * pass it on as a signal.
618 status
= omapi_connection_connect_internal (h
);
619 if (status
== ISC_R_INPROGRESS
)
620 return ISC_R_INPROGRESS
;
622 if (status
!= ISC_R_SUCCESS
)
623 omapi_signal (h
, "status", status
);
625 return ISC_R_SUCCESS
;
628 static isc_result_t
omapi_connection_connect_internal (omapi_object_t
*h
)
631 omapi_connection_object_t
*c
;
635 if (h
-> type
!= omapi_type_connection
)
636 return DHCP_R_INVALIDARG
;
637 c
= (omapi_connection_object_t
*)h
;
639 if (c
-> state
== omapi_connection_connecting
) {
641 if (getsockopt (c
-> socket
, SOL_SOCKET
, SO_ERROR
,
642 (char *)&error
, &sl
) < 0) {
643 omapi_disconnect (h
, 1);
644 return ISC_R_SUCCESS
;
647 c
-> state
= omapi_connection_connected
;
649 if (c
-> state
== omapi_connection_connecting
||
650 c
-> state
== omapi_connection_unconnected
) {
651 if (c
-> cptr
>= c
-> connect_list
-> count
) {
654 status
= ISC_R_CONNREFUSED
;
657 status
= ISC_R_NETUNREACH
;
660 status
= uerr2isc (error
);
663 omapi_disconnect (h
, 1);
667 if (c
-> connect_list
-> addresses
[c
-> cptr
].addrtype
!=
669 omapi_disconnect (h
, 1);
670 return DHCP_R_INVALIDARG
;
673 memcpy (&c
-> remote_addr
.sin_addr
,
674 &c
-> connect_list
-> addresses
[c
-> cptr
].address
,
675 sizeof c
-> remote_addr
.sin_addr
);
676 c
-> remote_addr
.sin_family
= AF_INET
;
677 c
-> remote_addr
.sin_port
=
678 htons (c
-> connect_list
-> addresses
[c
-> cptr
].port
);
679 #if defined (HAVE_SA_LEN)
680 c
-> remote_addr
.sin_len
= sizeof c
-> remote_addr
;
682 memset (&c
-> remote_addr
.sin_zero
, 0,
683 sizeof c
-> remote_addr
.sin_zero
);
686 error
= connect (c
-> socket
,
687 (struct sockaddr
*)&c
-> remote_addr
,
688 sizeof c
-> remote_addr
);
691 if (error
!= EINPROGRESS
) {
692 omapi_disconnect (h
, 1);
695 status
= ISC_R_CONNREFUSED
;
698 status
= ISC_R_NETUNREACH
;
701 status
= uerr2isc (error
);
706 c
-> state
= omapi_connection_connecting
;
707 return DHCP_R_INCOMPLETE
;
709 c
-> state
= omapi_connection_connected
;
712 /* I don't know why this would fail, so I'm tempted not to test
714 sl
= sizeof (c
-> local_addr
);
715 if (getsockname (c
-> socket
,
716 (struct sockaddr
*)&c
-> local_addr
, &sl
) < 0) {
719 /* Reregister with the I/O object. If we don't already have an
720 I/O object this turns into a register call, otherwise we simply
721 modify the pointers in the I/O object. */
723 status
= omapi_reregister_io_object (h
,
724 omapi_connection_readfd
,
725 omapi_connection_writefd
,
726 omapi_connection_reader
,
727 omapi_connection_writer
,
728 omapi_connection_reaper
);
730 if (status
!= ISC_R_SUCCESS
) {
731 omapi_disconnect (h
, 1);
735 omapi_signal_in (h
, "connect");
736 omapi_addr_list_dereference (&c
-> connect_list
, MDL
);
737 return ISC_R_INPROGRESS
;
740 /* Reaper function for connection - if the connection is completely closed,
741 reap it. If it's in the disconnecting state, there were bytes left
742 to write when the user closed it, so if there are now no bytes left to
743 write, we can close it. */
744 isc_result_t
omapi_connection_reaper (omapi_object_t
*h
)
746 omapi_connection_object_t
*c
;
748 if (h
-> type
!= omapi_type_connection
)
749 return DHCP_R_INVALIDARG
;
751 c
= (omapi_connection_object_t
*)h
;
752 if (c
-> state
== omapi_connection_disconnecting
&&
753 c
-> out_bytes
== 0) {
754 #ifdef DEBUG_PROTOCOL
755 log_debug ("omapi_connection_reaper(): disconnect");
757 omapi_disconnect (h
, 1);
759 if (c
-> state
== omapi_connection_closed
) {
760 #ifdef DEBUG_PROTOCOL
761 log_debug ("omapi_connection_reaper(): closed");
763 return ISC_R_NOTCONNECTED
;
765 return ISC_R_SUCCESS
;
768 static isc_result_t
make_dst_key (dst_key_t
**dst_key
, omapi_object_t
*a
) {
769 omapi_value_t
*key
= 0;
771 char *algorithm_str
= 0;
772 isc_result_t status
= ISC_R_SUCCESS
;
774 /* Get the key name as a C string. */
775 status
= ctring_from_attribute(a
, "name", &name_str
);
776 if (status
== ISC_R_SUCCESS
) {
777 /* Get the algorithm name as a C string. */
778 status
= ctring_from_attribute(a
, "algorithm", &algorithm_str
);
779 if (status
== ISC_R_SUCCESS
) {
780 /* Get the key secret value */
781 status
= omapi_get_value_str(a
, 0, "key", &key
);
782 if (status
== ISC_R_SUCCESS
) {
783 /* Now let's try and create the key */
784 status
= isclib_make_dst_key(
787 key
->value
->u
.buffer
.value
,
788 key
->value
->u
.buffer
.len
,
791 if (*dst_key
== NULL
) {
792 status
= ISC_R_NOMEMORY
;
799 dfree (name_str
, MDL
);
801 dfree (algorithm_str
, MDL
);
803 omapi_value_dereference (&key
, MDL
);
808 isc_result_t
omapi_connection_sign_data (int mode
,
811 const unsigned char *data
,
813 omapi_typed_data_t
**result
)
815 omapi_typed_data_t
*td
= (omapi_typed_data_t
*)0;
817 dst_context_t
**dctx
= (dst_context_t
**)context
;
819 /* Create the context for the dst module */
820 if (mode
& SIG_MODE_INIT
) {
821 status
= dst_context_create(key
, dhcp_gbl_ctx
.mctx
, dctx
);
822 if (status
!= ISC_R_SUCCESS
) {
827 /* If we have any data add it to the context */
830 region
.base
= (unsigned char *)data
;
832 dst_context_adddata(*dctx
, ®ion
);
835 /* Finish the signature and clean up the context */
836 if (mode
& SIG_MODE_FINAL
) {
837 unsigned int sigsize
;
840 status
= dst_key_sigsize(key
, &sigsize
);
841 if (status
!= ISC_R_SUCCESS
) {
845 status
= omapi_typed_data_new (MDL
, &td
,
848 if (status
!= ISC_R_SUCCESS
) {
852 isc_buffer_init(&sigbuf
, td
->u
.buffer
.value
, td
->u
.buffer
.len
);
853 status
= dst_context_sign(*dctx
, &sigbuf
);
854 if (status
!= ISC_R_SUCCESS
) {
859 omapi_typed_data_reference (result
, td
, MDL
);
863 /* We are done with the context and the td. On success
864 * the td is now referenced from result, on failure we
865 * don't need it any more */
867 omapi_typed_data_dereference (&td
, MDL
);
869 dst_context_destroy(dctx
);
873 return ISC_R_SUCCESS
;
876 isc_result_t
omapi_connection_output_auth_length (omapi_object_t
*h
,
879 omapi_connection_object_t
*c
;
881 if (h
->type
!= omapi_type_connection
)
882 return DHCP_R_INVALIDARG
;
883 c
= (omapi_connection_object_t
*)h
;
885 if (c
->out_key
== NULL
)
886 return ISC_R_NOTFOUND
;
888 return(dst_key_sigsize(c
->out_key
, l
));
891 isc_result_t
omapi_connection_set_value (omapi_object_t
*h
,
893 omapi_data_string_t
*name
,
894 omapi_typed_data_t
*value
)
896 omapi_connection_object_t
*c
;
899 if (h
-> type
!= omapi_type_connection
)
900 return DHCP_R_INVALIDARG
;
901 c
= (omapi_connection_object_t
*)h
;
903 if (omapi_ds_strcmp (name
, "input-authenticator") == 0) {
904 if (value
&& value
-> type
!= omapi_datatype_object
)
905 return DHCP_R_INVALIDARG
;
907 if (c
-> in_context
) {
908 omapi_connection_sign_data (SIG_MODE_FINAL
,
912 (omapi_typed_data_t
**) 0);
915 if (c
->in_key
!= NULL
) {
916 dst_key_free(&c
->in_key
);
920 status
= make_dst_key (&c
-> in_key
,
922 if (status
!= ISC_R_SUCCESS
)
926 return ISC_R_SUCCESS
;
928 else if (omapi_ds_strcmp (name
, "output-authenticator") == 0) {
929 if (value
&& value
-> type
!= omapi_datatype_object
)
930 return DHCP_R_INVALIDARG
;
932 if (c
-> out_context
) {
933 omapi_connection_sign_data (SIG_MODE_FINAL
,
937 (omapi_typed_data_t
**) 0);
940 if (c
->out_key
!= NULL
) {
941 dst_key_free(&c
->out_key
);
945 status
= make_dst_key (&c
-> out_key
,
947 if (status
!= ISC_R_SUCCESS
)
951 return ISC_R_SUCCESS
;
954 if (h
-> inner
&& h
-> inner
-> type
-> set_value
)
955 return (*(h
-> inner
-> type
-> set_value
))
956 (h
-> inner
, id
, name
, value
);
957 return ISC_R_NOTFOUND
;
960 isc_result_t
omapi_connection_get_value (omapi_object_t
*h
,
962 omapi_data_string_t
*name
,
963 omapi_value_t
**value
)
965 omapi_connection_object_t
*c
;
966 omapi_typed_data_t
*td
= (omapi_typed_data_t
*)0;
968 unsigned int sigsize
;
970 if (h
-> type
!= omapi_type_connection
)
971 return DHCP_R_INVALIDARG
;
972 c
= (omapi_connection_object_t
*)h
;
974 if (omapi_ds_strcmp (name
, "input-signature") == 0) {
975 if (!c
-> in_key
|| !c
-> in_context
)
976 return ISC_R_NOTFOUND
;
978 status
= omapi_connection_sign_data (SIG_MODE_FINAL
,
982 if (status
!= ISC_R_SUCCESS
)
985 status
= omapi_make_value (value
, name
, td
, MDL
);
986 omapi_typed_data_dereference (&td
, MDL
);
989 } else if (omapi_ds_strcmp (name
, "input-signature-size") == 0) {
990 if (c
->in_key
== NULL
)
991 return ISC_R_NOTFOUND
;
993 status
= dst_key_sigsize(c
->in_key
, &sigsize
);
994 if (status
!= ISC_R_SUCCESS
) {
998 return omapi_make_int_value(value
, name
, sigsize
, MDL
);
1000 } else if (omapi_ds_strcmp (name
, "output-signature") == 0) {
1001 if (!c
-> out_key
|| !c
-> out_context
)
1002 return ISC_R_NOTFOUND
;
1004 status
= omapi_connection_sign_data (SIG_MODE_FINAL
,
1008 if (status
!= ISC_R_SUCCESS
)
1011 status
= omapi_make_value (value
, name
, td
, MDL
);
1012 omapi_typed_data_dereference (&td
, MDL
);
1015 } else if (omapi_ds_strcmp (name
, "output-signature-size") == 0) {
1016 if (c
->out_key
== NULL
)
1017 return ISC_R_NOTFOUND
;
1020 status
= dst_key_sigsize(c
->out_key
, &sigsize
);
1021 if (status
!= ISC_R_SUCCESS
) {
1025 return omapi_make_int_value(value
, name
, sigsize
, MDL
);
1028 if (h
-> inner
&& h
-> inner
-> type
-> get_value
)
1029 return (*(h
-> inner
-> type
-> get_value
))
1030 (h
-> inner
, id
, name
, value
);
1031 return ISC_R_NOTFOUND
;
1034 isc_result_t
omapi_connection_destroy (omapi_object_t
*h
,
1035 const char *file
, int line
)
1037 omapi_connection_object_t
*c
;
1039 #ifdef DEBUG_PROTOCOL
1040 log_debug ("omapi_connection_destroy()");
1043 if (h
-> type
!= omapi_type_connection
)
1044 return ISC_R_UNEXPECTED
;
1045 c
= (omapi_connection_object_t
*)(h
);
1046 if (c
-> state
== omapi_connection_connected
)
1047 omapi_disconnect (h
, 1);
1049 omapi_listener_dereference (&c
-> listener
, file
, line
);
1050 if (c
-> connect_list
)
1051 omapi_addr_list_dereference (&c
-> connect_list
, file
, line
);
1052 return ISC_R_SUCCESS
;
1055 isc_result_t
omapi_connection_signal_handler (omapi_object_t
*h
,
1056 const char *name
, va_list ap
)
1058 if (h
-> type
!= omapi_type_connection
)
1059 return DHCP_R_INVALIDARG
;
1061 #ifdef DEBUG_PROTOCOL
1062 log_debug ("omapi_connection_signal_handler(%s)", name
);
1065 if (h
-> inner
&& h
-> inner
-> type
-> signal_handler
)
1066 return (*(h
-> inner
-> type
-> signal_handler
)) (h
-> inner
,
1068 return ISC_R_NOTFOUND
;
1071 /* Write all the published values associated with the object through the
1072 specified connection. */
1074 isc_result_t
omapi_connection_stuff_values (omapi_object_t
*c
,
1078 if (m
-> type
!= omapi_type_connection
)
1079 return DHCP_R_INVALIDARG
;
1081 if (m
-> inner
&& m
-> inner
-> type
-> stuff_values
)
1082 return (*(m
-> inner
-> type
-> stuff_values
)) (c
, id
,
1084 return ISC_R_SUCCESS
;
1087 /* @brief Fetches the value of an attribute in an object as an allocated
1090 * @param obj ompapi object containing the desire attribute
1091 * @param attr_name name of the desired attribute
1092 * @param[out] cstr pointer in which to place the allocated C string's address
1094 * Caller is responsible for freeing (via dfree) the allocated string.
1096 * @return ISC_R_SUCCESS if successful, otherwise indicates the type of failure
1098 static isc_result_t
ctring_from_attribute(omapi_object_t
*obj
, char *attr_name
,
1100 isc_result_t status
= ISC_R_SUCCESS
;
1101 omapi_value_t
*attr
= 0;
1103 /* Find the attribute in the object. */
1104 status
= omapi_get_value_str(obj
, (omapi_object_t
*)0, attr_name
,
1106 if (status
!= ISC_R_SUCCESS
) {
1110 /* Got it, let's make sure it's either data or string type. */
1111 if (attr
->value
->type
!= omapi_datatype_data
&&
1112 attr
->value
->type
!= omapi_datatype_string
) {
1113 return (DHCP_R_INVALIDARG
);
1116 /* Make a C string from the attribute value. */
1117 *cstr
= dmalloc (attr
->value
->u
.buffer
.len
+ 1, MDL
);
1119 status
= ISC_R_NOMEMORY
;
1121 memcpy (*cstr
, attr
->value
->u
.buffer
.value
,
1122 attr
->value
->u
.buffer
.len
);
1123 (*cstr
)[attr
->value
->u
.buffer
.len
] = 0;
1126 /* Get rid of the attribute reference */
1128 omapi_value_dereference (&attr
, MDL
);