3 Subroutines for dealing with connections. */
6 * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1999-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
24 * Redwood City, CA 94063
26 * https://www.isc.org/
32 #include <omapip/omapip_p.h>
33 #include <arpa/inet.h>
34 #include <arpa/nameser.h>
38 static void trace_connect_input (trace_type_t
*, unsigned, char *);
39 static void trace_connect_stop (trace_type_t
*);
40 static void trace_disconnect_input (trace_type_t
*, unsigned, char *);
41 static void trace_disconnect_stop (trace_type_t
*);
42 trace_type_t
*trace_connect
;
43 trace_type_t
*trace_disconnect
;
44 extern omapi_array_t
*trace_listeners
;
46 static isc_result_t
omapi_connection_connect_internal (omapi_object_t
*);
48 OMAPI_OBJECT_ALLOC (omapi_connection
,
49 omapi_connection_object_t
, omapi_type_connection
)
51 isc_result_t
omapi_connect (omapi_object_t
*c
,
52 const char *server_name
,
57 omapi_addr_list_t
*addrs
= (omapi_addr_list_t
*)0;
62 log_debug ("omapi_connect(%s, port=%d)", server_name
, port
);
65 if (!inet_aton (server_name
, &foo
)) {
66 /* If we didn't get a numeric address, try for a domain
67 name. It's okay for this call to block. */
68 he
= gethostbyname (server_name
);
70 return DHCP_R_HOSTUNKNOWN
;
71 for (i
= 0; he
-> h_addr_list
[i
]; i
++)
74 return DHCP_R_HOSTUNKNOWN
;
77 status
= omapi_addr_list_new (&addrs
, hix
, MDL
);
78 if (status
!= ISC_R_SUCCESS
)
80 for (i
= 0; i
< hix
; i
++) {
81 addrs
-> addresses
[i
].addrtype
= he
-> h_addrtype
;
82 addrs
-> addresses
[i
].addrlen
= he
-> h_length
;
83 memcpy (addrs
-> addresses
[i
].address
,
84 he
-> h_addr_list
[i
],
85 (unsigned)he
-> h_length
);
86 addrs
-> addresses
[i
].port
= port
;
89 status
= omapi_addr_list_new (&addrs
, 1, MDL
);
90 if (status
!= ISC_R_SUCCESS
)
92 addrs
-> addresses
[0].addrtype
= AF_INET
;
93 addrs
-> addresses
[0].addrlen
= sizeof foo
;
94 memcpy (addrs
-> addresses
[0].address
, &foo
, sizeof foo
);
95 addrs
-> addresses
[0].port
= port
;
97 status
= omapi_connect_list (c
, addrs
, (omapi_addr_t
*)0);
98 omapi_addr_list_dereference (&addrs
, MDL
);
102 isc_result_t
omapi_connect_list (omapi_object_t
*c
,
103 omapi_addr_list_t
*remote_addrs
,
104 omapi_addr_t
*local_addr
)
107 omapi_connection_object_t
*obj
;
109 struct sockaddr_in local_sin
;
111 obj
= (omapi_connection_object_t
*)0;
112 status
= omapi_connection_allocate (&obj
, MDL
);
113 if (status
!= ISC_R_SUCCESS
)
116 status
= omapi_object_reference (&c
-> outer
, (omapi_object_t
*)obj
,
118 if (status
!= ISC_R_SUCCESS
) {
119 omapi_connection_dereference (&obj
, MDL
);
122 status
= omapi_object_reference (&obj
-> inner
, c
, MDL
);
123 if (status
!= ISC_R_SUCCESS
) {
124 omapi_connection_dereference (&obj
, MDL
);
128 /* Store the address list on the object. */
129 omapi_addr_list_reference (&obj
-> connect_list
, remote_addrs
, MDL
);
131 obj
-> state
= omapi_connection_unconnected
;
133 #if defined (TRACING)
134 /* If we're playing back, don't actually try to connect - just leave
135 the object available for a subsequent connect or disconnect. */
136 if (!trace_playback ()) {
138 /* Create a socket on which to communicate. */
140 socket (PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
141 if (obj
-> socket
< 0) {
142 omapi_connection_dereference (&obj
, MDL
);
143 if (errno
== EMFILE
|| errno
== ENFILE
145 return ISC_R_NORESOURCES
;
146 return ISC_R_UNEXPECTED
;
149 /* Set up the local address, if any. */
151 /* Only do TCPv4 so far. */
152 if (local_addr
-> addrtype
!= AF_INET
) {
154 omapi_connection_dereference (&obj
, MDL
);
155 return DHCP_R_INVALIDARG
;
157 local_sin
.sin_port
= htons (local_addr
-> port
);
158 memcpy (&local_sin
.sin_addr
,
159 local_addr
-> address
,
160 local_addr
-> addrlen
);
161 #if defined (HAVE_SA_LEN)
162 local_sin
.sin_len
= sizeof local_addr
;
164 local_sin
.sin_family
= AF_INET
;
165 memset (&local_sin
.sin_zero
, 0,
166 sizeof local_sin
.sin_zero
);
168 if (bind (obj
-> socket
, (struct sockaddr
*)&local_sin
,
169 sizeof local_sin
) < 0) {
170 omapi_connection_object_t
**objp
= &obj
;
171 omapi_object_t
**o
= (omapi_object_t
**)objp
;
173 omapi_object_dereference(o
, MDL
);
174 if (errno
== EADDRINUSE
)
175 return ISC_R_ADDRINUSE
;
176 if (errno
== EADDRNOTAVAIL
)
177 return ISC_R_ADDRNOTAVAIL
;
180 return ISC_R_UNEXPECTED
;
182 obj
-> local_addr
= local_sin
;
186 if (fcntl (obj
-> socket
, F_SETFD
, 1) < 0) {
187 close (obj
-> socket
);
188 omapi_connection_dereference (&obj
, MDL
);
189 return ISC_R_UNEXPECTED
;
193 /* Set the SO_REUSEADDR flag (this should not fail). */
195 if (setsockopt (obj
-> socket
, SOL_SOCKET
, SO_REUSEADDR
,
196 (char *)&flag
, sizeof flag
) < 0) {
197 omapi_connection_dereference (&obj
, MDL
);
198 return ISC_R_UNEXPECTED
;
201 /* Set the file to nonblocking mode. */
202 if (fcntl (obj
-> socket
, F_SETFL
, O_NONBLOCK
) < 0) {
203 omapi_connection_dereference (&obj
, MDL
);
204 return ISC_R_UNEXPECTED
;
209 * If available stop the OS from killing our
210 * program on a SIGPIPE failure
213 if (setsockopt(obj
->socket
, SOL_SOCKET
, SO_NOSIGPIPE
,
214 (char *)&flag
, sizeof(flag
)) < 0) {
215 omapi_connection_dereference (&obj
, MDL
);
216 return ISC_R_UNEXPECTED
;
220 status
= (omapi_register_io_object
221 ((omapi_object_t
*)obj
,
222 0, omapi_connection_writefd
,
223 0, omapi_connection_connect
,
224 omapi_connection_reaper
));
225 if (status
!= ISC_R_SUCCESS
)
227 status
= omapi_connection_connect_internal ((omapi_object_t
*)
230 * inprogress is the same as success but used
231 * to indicate to the dispatch code that we should
232 * mark the socket as requiring more attention.
233 * Routines calling this function should handle
236 if (status
== ISC_R_INPROGRESS
) {
237 status
= ISC_R_SUCCESS
;
239 #if defined (TRACING)
241 omapi_connection_register (obj
, MDL
);
245 omapi_connection_dereference (&obj
, MDL
);
249 #if defined (TRACING)
250 omapi_array_t
*omapi_connections
;
252 OMAPI_ARRAY_TYPE(omapi_connection
, omapi_connection_object_t
)
254 void omapi_connection_trace_setup (void) {
255 trace_connect
= trace_type_register ("connect", (void *)0,
257 trace_connect_stop
, MDL
);
258 trace_disconnect
= trace_type_register ("disconnect", (void *)0,
259 trace_disconnect_input
,
260 trace_disconnect_stop
, MDL
);
263 void omapi_connection_register (omapi_connection_object_t
*obj
,
264 const char *file
, int line
)
269 int32_t connect_index
, listener_index
;
270 static int32_t index
;
272 if (!omapi_connections
) {
273 status
= omapi_connection_array_allocate (&omapi_connections
,
275 if (status
!= ISC_R_SUCCESS
)
279 status
= omapi_connection_array_extend (omapi_connections
, obj
,
280 (int *)0, file
, line
);
281 if (status
!= ISC_R_SUCCESS
) {
286 #if defined (TRACING)
287 if (trace_record ()) {
288 /* Connection registration packet:
291 int32_t listener_index [-1 means no listener]
292 u_int16_t remote_port
294 u_int32_t remote_addr
295 u_int32_t local_addr */
297 connect_index
= htonl (index
);
300 listener_index
= htonl (obj
-> listener
-> index
);
302 listener_index
= htonl (-1);
303 iov
[iov_count
].buf
= (char *)&connect_index
;
304 iov
[iov_count
++].len
= sizeof connect_index
;
305 iov
[iov_count
].buf
= (char *)&listener_index
;
306 iov
[iov_count
++].len
= sizeof listener_index
;
307 iov
[iov_count
].buf
= (char *)&obj
-> remote_addr
.sin_port
;
308 iov
[iov_count
++].len
= sizeof obj
-> remote_addr
.sin_port
;
309 iov
[iov_count
].buf
= (char *)&obj
-> local_addr
.sin_port
;
310 iov
[iov_count
++].len
= sizeof obj
-> local_addr
.sin_port
;
311 iov
[iov_count
].buf
= (char *)&obj
-> remote_addr
.sin_addr
;
312 iov
[iov_count
++].len
= sizeof obj
-> remote_addr
.sin_addr
;
313 iov
[iov_count
].buf
= (char *)&obj
-> local_addr
.sin_addr
;
314 iov
[iov_count
++].len
= sizeof obj
-> local_addr
.sin_addr
;
316 status
= trace_write_packet_iov (trace_connect
,
317 iov_count
, iov
, file
, line
);
322 static void trace_connect_input (trace_type_t
*ttype
,
323 unsigned length
, char *buf
)
325 struct sockaddr_in remote
, local
;
326 int32_t connect_index
, listener_index
;
328 omapi_connection_object_t
*obj
;
332 if (length
!= ((sizeof connect_index
) +
333 (sizeof remote
.sin_port
) +
334 (sizeof remote
.sin_addr
)) * 2) {
335 log_error ("Trace connect: invalid length %d", length
);
339 memset (&remote
, 0, sizeof remote
);
340 memset (&local
, 0, sizeof local
);
341 memcpy (&connect_index
, s
, sizeof connect_index
);
342 s
+= sizeof connect_index
;
343 memcpy (&listener_index
, s
, sizeof listener_index
);
344 s
+= sizeof listener_index
;
345 memcpy (&remote
.sin_port
, s
, sizeof remote
.sin_port
);
346 s
+= sizeof remote
.sin_port
;
347 memcpy (&local
.sin_port
, s
, sizeof local
.sin_port
);
348 s
+= sizeof local
.sin_port
;
349 memcpy (&remote
.sin_addr
, s
, sizeof remote
.sin_addr
);
350 s
+= sizeof remote
.sin_addr
;
351 memcpy (&local
.sin_addr
, s
, sizeof local
.sin_addr
);
352 s
+= sizeof local
.sin_addr
;
355 connect_index
= ntohl (connect_index
);
356 listener_index
= ntohl (listener_index
);
358 /* If this was a connect to a listener, then we just slap together
360 if (listener_index
!= -1) {
361 omapi_listener_object_t
*listener
;
362 listener
= (omapi_listener_object_t
*)0;
363 omapi_array_foreach_begin (trace_listeners
,
364 omapi_listener_object_t
, lp
) {
365 if (lp
-> address
.sin_port
== local
.sin_port
) {
366 omapi_listener_reference (&listener
, lp
, MDL
);
367 omapi_listener_dereference (&lp
, MDL
);
370 } omapi_array_foreach_end (trace_listeners
,
371 omapi_listener_object_t
, lp
);
373 log_error ("%s%ld, addr %s, port %d",
374 "Spurious traced listener connect - index ",
375 (long int)listener_index
,
376 inet_ntoa (local
.sin_addr
),
377 ntohs (local
.sin_port
));
380 obj
= (omapi_connection_object_t
*)0;
381 status
= omapi_listener_connect (&obj
, listener
, -1, &remote
);
382 if (status
!= ISC_R_SUCCESS
) {
383 log_error ("traced listener connect: %s",
384 isc_result_totext (status
));
387 omapi_connection_dereference (&obj
, MDL
);
388 omapi_listener_dereference (&listener
, MDL
);
392 /* Find the matching connect object, if there is one. */
393 omapi_array_foreach_begin (omapi_connections
,
394 omapi_connection_object_t
, lp
) {
395 for (i
= 0; (lp
->connect_list
&&
396 i
< lp
->connect_list
->count
); i
++) {
397 if (!memcmp (&remote
.sin_addr
,
398 &lp
->connect_list
->addresses
[i
].address
,
399 sizeof remote
.sin_addr
) &&
400 (ntohs (remote
.sin_port
) ==
401 lp
->connect_list
->addresses
[i
].port
)) {
402 lp
->state
= omapi_connection_connected
;
403 lp
->remote_addr
= remote
;
404 lp
->remote_addr
.sin_family
= AF_INET
;
405 omapi_addr_list_dereference(&lp
->connect_list
, MDL
);
406 lp
->index
= connect_index
;
407 status
= omapi_signal_in((omapi_object_t
*)lp
,
409 omapi_connection_dereference (&lp
, MDL
);
413 } omapi_array_foreach_end (omapi_connections
,
414 omapi_connection_object_t
, lp
);
416 log_error ("Spurious traced connect - index %ld, addr %s, port %d",
417 (long int)connect_index
, inet_ntoa (remote
.sin_addr
),
418 ntohs (remote
.sin_port
));
422 static void trace_connect_stop (trace_type_t
*ttype
) { }
424 static void trace_disconnect_input (trace_type_t
*ttype
,
425 unsigned length
, char *buf
)
428 if (length
!= sizeof *index
) {
429 log_error ("trace disconnect: wrong length %d", length
);
433 index
= (int32_t *)buf
;
435 omapi_array_foreach_begin (omapi_connections
,
436 omapi_connection_object_t
, lp
) {
437 if (lp
-> index
== ntohl (*index
)) {
438 omapi_disconnect ((omapi_object_t
*)lp
, 1);
439 omapi_connection_dereference (&lp
, MDL
);
442 } omapi_array_foreach_end (omapi_connections
,
443 omapi_connection_object_t
, lp
);
445 log_error ("trace disconnect: no connection matching index %ld",
446 (long int)ntohl (*index
));
449 static void trace_disconnect_stop (trace_type_t
*ttype
) { }
452 /* Disconnect a connection object from the remote end. If force is nonzero,
453 close the connection immediately. Otherwise, shut down the receiving end
454 but allow any unsent data to be sent before actually closing the socket. */
456 isc_result_t
omapi_disconnect (omapi_object_t
*h
,
459 omapi_connection_object_t
*c
;
461 #ifdef DEBUG_PROTOCOL
462 log_debug ("omapi_disconnect(%s)", force
? "force" : "");
465 c
= (omapi_connection_object_t
*)h
;
466 if (c
-> type
!= omapi_type_connection
)
467 return DHCP_R_INVALIDARG
;
469 #if defined (TRACING)
470 if (trace_record ()) {
474 index
= htonl (c
-> index
);
475 status
= trace_write_packet (trace_disconnect
,
476 sizeof index
, (char *)&index
,
478 if (status
!= ISC_R_SUCCESS
) {
480 log_error ("trace_write_packet: %s",
481 isc_result_totext (status
));
484 if (!trace_playback ()) {
487 /* If we're already disconnecting, we don't have to do
489 if (c
-> state
== omapi_connection_disconnecting
)
490 return ISC_R_SUCCESS
;
492 /* Try to shut down the socket - this sends a FIN to
493 the remote end, so that it won't send us any more
494 data. If the shutdown succeeds, and we still
495 have bytes left to write, defer closing the socket
496 until that's done. */
497 if (!shutdown (c
-> socket
, SHUT_RD
)) {
498 if (c
-> out_bytes
> 0) {
500 omapi_connection_disconnecting
;
501 return ISC_R_SUCCESS
;
506 #if defined (TRACING)
509 c
-> state
= omapi_connection_closed
;
513 * Disconnecting from the I/O object seems incorrect as it doesn't
514 * cause the I/O object to be cleaned and released. Previous to
515 * using the isc socket library this wouldn't have caused a problem
516 * with the socket library we would have a reference to a closed
517 * socket. Instead we now do an unregister to properly free the
521 /* Disconnect from I/O object, if any. */
523 if (h
-> outer
-> inner
)
524 omapi_object_dereference (&h
-> outer
-> inner
, MDL
);
525 omapi_object_dereference (&h
-> outer
, MDL
);
529 omapi_unregister_io_object(h
);
533 /* If whatever created us registered a signal handler, send it
534 a disconnect signal. */
535 omapi_signal (h
, "disconnect", h
);
537 /* Disconnect from protocol object, if any. */
538 if (h
->inner
!= NULL
) {
539 if (h
->inner
->outer
!= NULL
) {
540 omapi_object_dereference(&h
->inner
->outer
, MDL
);
542 omapi_object_dereference(&h
->inner
, MDL
);
545 /* XXX: the code to free buffers should be in the dereference
546 function, but there is no special-purpose function to
547 dereference connections, so these just get leaked */
548 /* Free any buffers */
549 if (c
->inbufs
!= NULL
) {
550 omapi_buffer_dereference(&c
->inbufs
, MDL
);
553 if (c
->outbufs
!= NULL
) {
554 omapi_buffer_dereference(&c
->outbufs
, MDL
);
558 return ISC_R_SUCCESS
;
561 isc_result_t
omapi_connection_require (omapi_object_t
*h
, unsigned bytes
)
563 omapi_connection_object_t
*c
;
565 if (h
-> type
!= omapi_type_connection
)
566 return DHCP_R_INVALIDARG
;
567 c
= (omapi_connection_object_t
*)h
;
569 c
-> bytes_needed
= bytes
;
570 if (c
-> bytes_needed
<= c
-> in_bytes
) {
571 return ISC_R_SUCCESS
;
573 return DHCP_R_NOTYET
;
576 /* Return the socket on which the dispatcher should wait for readiness
577 to read, for a connection object. */
578 int omapi_connection_readfd (omapi_object_t
*h
)
580 omapi_connection_object_t
*c
;
581 if (h
-> type
!= omapi_type_connection
)
583 c
= (omapi_connection_object_t
*)h
;
584 if (c
-> state
!= omapi_connection_connected
)
590 * Return the socket on which the dispatcher should wait for readiness
591 * to write, for a connection object. When bytes are buffered we should
592 * also poke the dispatcher to tell it to start or re-start watching the
595 int omapi_connection_writefd (omapi_object_t
*h
)
597 omapi_connection_object_t
*c
;
598 if (h
-> type
!= omapi_type_connection
)
600 c
= (omapi_connection_object_t
*)h
;
604 isc_result_t
omapi_connection_connect (omapi_object_t
*h
)
609 * We use the INPROGRESS status to indicate that
610 * we want more from the socket. In this case we
611 * have now connected and are trying to write to
612 * the socket for the first time. For the signaling
613 * code this is the same as a SUCCESS so we don't
614 * pass it on as a signal.
616 status
= omapi_connection_connect_internal (h
);
617 if (status
== ISC_R_INPROGRESS
)
618 return ISC_R_INPROGRESS
;
620 if (status
!= ISC_R_SUCCESS
)
621 omapi_signal (h
, "status", status
);
623 return ISC_R_SUCCESS
;
626 static isc_result_t
omapi_connection_connect_internal (omapi_object_t
*h
)
629 omapi_connection_object_t
*c
;
633 if (h
-> type
!= omapi_type_connection
)
634 return DHCP_R_INVALIDARG
;
635 c
= (omapi_connection_object_t
*)h
;
637 if (c
-> state
== omapi_connection_connecting
) {
639 if (getsockopt (c
-> socket
, SOL_SOCKET
, SO_ERROR
,
640 (char *)&error
, &sl
) < 0) {
641 omapi_disconnect (h
, 1);
642 return ISC_R_SUCCESS
;
645 c
-> state
= omapi_connection_connected
;
647 if (c
-> state
== omapi_connection_connecting
||
648 c
-> state
== omapi_connection_unconnected
) {
649 if (c
-> cptr
>= c
-> connect_list
-> count
) {
652 status
= ISC_R_CONNREFUSED
;
655 status
= ISC_R_NETUNREACH
;
658 status
= uerr2isc (error
);
661 omapi_disconnect (h
, 1);
665 if (c
-> connect_list
-> addresses
[c
-> cptr
].addrtype
!=
667 omapi_disconnect (h
, 1);
668 return DHCP_R_INVALIDARG
;
671 memcpy (&c
-> remote_addr
.sin_addr
,
672 &c
-> connect_list
-> addresses
[c
-> cptr
].address
,
673 sizeof c
-> remote_addr
.sin_addr
);
674 c
-> remote_addr
.sin_family
= AF_INET
;
675 c
-> remote_addr
.sin_port
=
676 htons (c
-> connect_list
-> addresses
[c
-> cptr
].port
);
677 #if defined (HAVE_SA_LEN)
678 c
-> remote_addr
.sin_len
= sizeof c
-> remote_addr
;
680 memset (&c
-> remote_addr
.sin_zero
, 0,
681 sizeof c
-> remote_addr
.sin_zero
);
684 error
= connect (c
-> socket
,
685 (struct sockaddr
*)&c
-> remote_addr
,
686 sizeof c
-> remote_addr
);
689 if (error
!= EINPROGRESS
) {
690 omapi_disconnect (h
, 1);
693 status
= ISC_R_CONNREFUSED
;
696 status
= ISC_R_NETUNREACH
;
699 status
= uerr2isc (error
);
704 c
-> state
= omapi_connection_connecting
;
705 return DHCP_R_INCOMPLETE
;
707 c
-> state
= omapi_connection_connected
;
710 /* I don't know why this would fail, so I'm tempted not to test
712 sl
= sizeof (c
-> local_addr
);
713 if (getsockname (c
-> socket
,
714 (struct sockaddr
*)&c
-> local_addr
, &sl
) < 0) {
717 /* Reregister with the I/O object. If we don't already have an
718 I/O object this turns into a register call, otherwise we simply
719 modify the pointers in the I/O object. */
721 status
= omapi_reregister_io_object (h
,
722 omapi_connection_readfd
,
723 omapi_connection_writefd
,
724 omapi_connection_reader
,
725 omapi_connection_writer
,
726 omapi_connection_reaper
);
728 if (status
!= ISC_R_SUCCESS
) {
729 omapi_disconnect (h
, 1);
733 omapi_signal_in (h
, "connect");
734 omapi_addr_list_dereference (&c
-> connect_list
, MDL
);
735 return ISC_R_INPROGRESS
;
738 /* Reaper function for connection - if the connection is completely closed,
739 reap it. If it's in the disconnecting state, there were bytes left
740 to write when the user closed it, so if there are now no bytes left to
741 write, we can close it. */
742 isc_result_t
omapi_connection_reaper (omapi_object_t
*h
)
744 omapi_connection_object_t
*c
;
746 if (h
-> type
!= omapi_type_connection
)
747 return DHCP_R_INVALIDARG
;
749 c
= (omapi_connection_object_t
*)h
;
750 if (c
-> state
== omapi_connection_disconnecting
&&
751 c
-> out_bytes
== 0) {
752 #ifdef DEBUG_PROTOCOL
753 log_debug ("omapi_connection_reaper(): disconnect");
755 omapi_disconnect (h
, 1);
757 if (c
-> state
== omapi_connection_closed
) {
758 #ifdef DEBUG_PROTOCOL
759 log_debug ("omapi_connection_reaper(): closed");
761 return ISC_R_NOTCONNECTED
;
763 return ISC_R_SUCCESS
;
766 static isc_result_t
make_dst_key (dst_key_t
**dst_key
, omapi_object_t
*a
) {
767 omapi_value_t
*name
= (omapi_value_t
*)0;
768 omapi_value_t
*algorithm
= (omapi_value_t
*)0;
769 omapi_value_t
*key
= (omapi_value_t
*)0;
770 char *name_str
= NULL
;
771 isc_result_t status
= ISC_R_SUCCESS
;
773 if (status
== ISC_R_SUCCESS
)
774 status
= omapi_get_value_str
775 (a
, (omapi_object_t
*)0, "name", &name
);
777 if (status
== ISC_R_SUCCESS
)
778 status
= omapi_get_value_str
779 (a
, (omapi_object_t
*)0, "algorithm", &algorithm
);
781 if (status
== ISC_R_SUCCESS
)
782 status
= omapi_get_value_str
783 (a
, (omapi_object_t
*)0, "key", &key
);
785 if (status
== ISC_R_SUCCESS
) {
786 if ((algorithm
->value
->type
!= omapi_datatype_data
&&
787 algorithm
->value
->type
!= omapi_datatype_string
) ||
788 strncasecmp((char *)algorithm
->value
->u
.buffer
.value
,
789 NS_TSIG_ALG_HMAC_MD5
".",
790 algorithm
->value
->u
.buffer
.len
) != 0) {
791 status
= DHCP_R_INVALIDARG
;
795 if (status
== ISC_R_SUCCESS
) {
796 name_str
= dmalloc (name
-> value
-> u
.buffer
.len
+ 1, MDL
);
798 status
= ISC_R_NOMEMORY
;
801 if (status
== ISC_R_SUCCESS
) {
803 name
-> value
-> u
.buffer
.value
,
804 name
-> value
-> u
.buffer
.len
);
805 name_str
[name
-> value
-> u
.buffer
.len
] = 0;
807 status
= isclib_make_dst_key(name_str
,
809 key
->value
->u
.buffer
.value
,
810 key
->value
->u
.buffer
.len
,
813 if (*dst_key
== NULL
)
814 status
= ISC_R_NOMEMORY
;
818 dfree (name_str
, MDL
);
820 omapi_value_dereference (&key
, MDL
);
822 omapi_value_dereference (&algorithm
, MDL
);
824 omapi_value_dereference (&name
, MDL
);
829 isc_result_t
omapi_connection_sign_data (int mode
,
832 const unsigned char *data
,
834 omapi_typed_data_t
**result
)
836 omapi_typed_data_t
*td
= (omapi_typed_data_t
*)0;
838 dst_context_t
**dctx
= (dst_context_t
**)context
;
840 /* Create the context for the dst module */
841 if (mode
& SIG_MODE_INIT
) {
842 status
= dst_context_create(key
, dhcp_gbl_ctx
.mctx
, dctx
);
843 if (status
!= ISC_R_SUCCESS
) {
848 /* If we have any data add it to the context */
851 region
.base
= (unsigned char *)data
;
853 dst_context_adddata(*dctx
, ®ion
);
856 /* Finish the signature and clean up the context */
857 if (mode
& SIG_MODE_FINAL
) {
858 unsigned int sigsize
;
861 status
= dst_key_sigsize(key
, &sigsize
);
862 if (status
!= ISC_R_SUCCESS
) {
866 status
= omapi_typed_data_new (MDL
, &td
,
869 if (status
!= ISC_R_SUCCESS
) {
873 isc_buffer_init(&sigbuf
, td
->u
.buffer
.value
, td
->u
.buffer
.len
);
874 status
= dst_context_sign(*dctx
, &sigbuf
);
875 if (status
!= ISC_R_SUCCESS
) {
880 omapi_typed_data_reference (result
, td
, MDL
);
884 /* We are done with the context and the td. On success
885 * the td is now referenced from result, on failure we
886 * don't need it any more */
888 omapi_typed_data_dereference (&td
, MDL
);
890 dst_context_destroy(dctx
);
894 return ISC_R_SUCCESS
;
897 isc_result_t
omapi_connection_output_auth_length (omapi_object_t
*h
,
900 omapi_connection_object_t
*c
;
902 if (h
->type
!= omapi_type_connection
)
903 return DHCP_R_INVALIDARG
;
904 c
= (omapi_connection_object_t
*)h
;
906 if (c
->out_key
== NULL
)
907 return ISC_R_NOTFOUND
;
909 return(dst_key_sigsize(c
->out_key
, l
));
912 isc_result_t
omapi_connection_set_value (omapi_object_t
*h
,
914 omapi_data_string_t
*name
,
915 omapi_typed_data_t
*value
)
917 omapi_connection_object_t
*c
;
920 if (h
-> type
!= omapi_type_connection
)
921 return DHCP_R_INVALIDARG
;
922 c
= (omapi_connection_object_t
*)h
;
924 if (omapi_ds_strcmp (name
, "input-authenticator") == 0) {
925 if (value
&& value
-> type
!= omapi_datatype_object
)
926 return DHCP_R_INVALIDARG
;
928 if (c
-> in_context
) {
929 omapi_connection_sign_data (SIG_MODE_FINAL
,
933 (omapi_typed_data_t
**) 0);
936 if (c
->in_key
!= NULL
) {
937 dst_key_free(&c
->in_key
);
941 status
= make_dst_key (&c
-> in_key
,
943 if (status
!= ISC_R_SUCCESS
)
947 return ISC_R_SUCCESS
;
949 else if (omapi_ds_strcmp (name
, "output-authenticator") == 0) {
950 if (value
&& value
-> type
!= omapi_datatype_object
)
951 return DHCP_R_INVALIDARG
;
953 if (c
-> out_context
) {
954 omapi_connection_sign_data (SIG_MODE_FINAL
,
958 (omapi_typed_data_t
**) 0);
961 if (c
->out_key
!= NULL
) {
962 dst_key_free(&c
->out_key
);
966 status
= make_dst_key (&c
-> out_key
,
968 if (status
!= ISC_R_SUCCESS
)
972 return ISC_R_SUCCESS
;
975 if (h
-> inner
&& h
-> inner
-> type
-> set_value
)
976 return (*(h
-> inner
-> type
-> set_value
))
977 (h
-> inner
, id
, name
, value
);
978 return ISC_R_NOTFOUND
;
981 isc_result_t
omapi_connection_get_value (omapi_object_t
*h
,
983 omapi_data_string_t
*name
,
984 omapi_value_t
**value
)
986 omapi_connection_object_t
*c
;
987 omapi_typed_data_t
*td
= (omapi_typed_data_t
*)0;
989 unsigned int sigsize
;
991 if (h
-> type
!= omapi_type_connection
)
992 return DHCP_R_INVALIDARG
;
993 c
= (omapi_connection_object_t
*)h
;
995 if (omapi_ds_strcmp (name
, "input-signature") == 0) {
996 if (!c
-> in_key
|| !c
-> in_context
)
997 return ISC_R_NOTFOUND
;
999 status
= omapi_connection_sign_data (SIG_MODE_FINAL
,
1003 if (status
!= ISC_R_SUCCESS
)
1006 status
= omapi_make_value (value
, name
, td
, MDL
);
1007 omapi_typed_data_dereference (&td
, MDL
);
1010 } else if (omapi_ds_strcmp (name
, "input-signature-size") == 0) {
1011 if (c
->in_key
== NULL
)
1012 return ISC_R_NOTFOUND
;
1014 status
= dst_key_sigsize(c
->in_key
, &sigsize
);
1015 if (status
!= ISC_R_SUCCESS
) {
1019 return omapi_make_int_value(value
, name
, sigsize
, MDL
);
1021 } else if (omapi_ds_strcmp (name
, "output-signature") == 0) {
1022 if (!c
-> out_key
|| !c
-> out_context
)
1023 return ISC_R_NOTFOUND
;
1025 status
= omapi_connection_sign_data (SIG_MODE_FINAL
,
1029 if (status
!= ISC_R_SUCCESS
)
1032 status
= omapi_make_value (value
, name
, td
, MDL
);
1033 omapi_typed_data_dereference (&td
, MDL
);
1036 } else if (omapi_ds_strcmp (name
, "output-signature-size") == 0) {
1037 if (c
->out_key
== NULL
)
1038 return ISC_R_NOTFOUND
;
1041 status
= dst_key_sigsize(c
->out_key
, &sigsize
);
1042 if (status
!= ISC_R_SUCCESS
) {
1046 return omapi_make_int_value(value
, name
, sigsize
, MDL
);
1049 if (h
-> inner
&& h
-> inner
-> type
-> get_value
)
1050 return (*(h
-> inner
-> type
-> get_value
))
1051 (h
-> inner
, id
, name
, value
);
1052 return ISC_R_NOTFOUND
;
1055 isc_result_t
omapi_connection_destroy (omapi_object_t
*h
,
1056 const char *file
, int line
)
1058 omapi_connection_object_t
*c
;
1060 #ifdef DEBUG_PROTOCOL
1061 log_debug ("omapi_connection_destroy()");
1064 if (h
-> type
!= omapi_type_connection
)
1065 return ISC_R_UNEXPECTED
;
1066 c
= (omapi_connection_object_t
*)(h
);
1067 if (c
-> state
== omapi_connection_connected
)
1068 omapi_disconnect (h
, 1);
1070 omapi_listener_dereference (&c
-> listener
, file
, line
);
1071 if (c
-> connect_list
)
1072 omapi_addr_list_dereference (&c
-> connect_list
, file
, line
);
1073 return ISC_R_SUCCESS
;
1076 isc_result_t
omapi_connection_signal_handler (omapi_object_t
*h
,
1077 const char *name
, va_list ap
)
1079 if (h
-> type
!= omapi_type_connection
)
1080 return DHCP_R_INVALIDARG
;
1082 #ifdef DEBUG_PROTOCOL
1083 log_debug ("omapi_connection_signal_handler(%s)", name
);
1086 if (h
-> inner
&& h
-> inner
-> type
-> signal_handler
)
1087 return (*(h
-> inner
-> type
-> signal_handler
)) (h
-> inner
,
1089 return ISC_R_NOTFOUND
;
1092 /* Write all the published values associated with the object through the
1093 specified connection. */
1095 isc_result_t
omapi_connection_stuff_values (omapi_object_t
*c
,
1099 if (m
-> type
!= omapi_type_connection
)
1100 return DHCP_R_INVALIDARG
;
1102 if (m
-> inner
&& m
-> inner
-> type
-> stuff_values
)
1103 return (*(m
-> inner
-> type
-> stuff_values
)) (c
, id
,
1105 return ISC_R_SUCCESS
;