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
) {
153 omapi_connection_dereference (&obj
, MDL
);
154 return DHCP_R_INVALIDARG
;
156 local_sin
.sin_port
= htons (local_addr
-> port
);
157 memcpy (&local_sin
.sin_addr
,
158 local_addr
-> address
,
159 local_addr
-> addrlen
);
160 #if defined (HAVE_SA_LEN)
161 local_sin
.sin_len
= sizeof local_addr
;
163 local_sin
.sin_family
= AF_INET
;
164 memset (&local_sin
.sin_zero
, 0,
165 sizeof local_sin
.sin_zero
);
167 if (bind (obj
-> socket
, (struct sockaddr
*)&local_sin
,
168 sizeof local_sin
) < 0) {
169 omapi_connection_object_t
**objp
= &obj
;
170 omapi_object_t
**o
= (omapi_object_t
**)objp
;
171 omapi_object_dereference(o
, MDL
);
172 if (errno
== EADDRINUSE
)
173 return ISC_R_ADDRINUSE
;
174 if (errno
== EADDRNOTAVAIL
)
175 return ISC_R_ADDRNOTAVAIL
;
178 return ISC_R_UNEXPECTED
;
180 obj
-> local_addr
= local_sin
;
184 if (fcntl (obj
-> socket
, F_SETFD
, 1) < 0) {
185 close (obj
-> socket
);
186 omapi_connection_dereference (&obj
, MDL
);
187 return ISC_R_UNEXPECTED
;
191 /* Set the SO_REUSEADDR flag (this should not fail). */
193 if (setsockopt (obj
-> socket
, SOL_SOCKET
, SO_REUSEADDR
,
194 (char *)&flag
, sizeof flag
) < 0) {
195 omapi_connection_dereference (&obj
, MDL
);
196 return ISC_R_UNEXPECTED
;
199 /* Set the file to nonblocking mode. */
200 if (fcntl (obj
-> socket
, F_SETFL
, O_NONBLOCK
) < 0) {
201 omapi_connection_dereference (&obj
, MDL
);
202 return ISC_R_UNEXPECTED
;
207 * If available stop the OS from killing our
208 * program on a SIGPIPE failure
211 if (setsockopt(obj
->socket
, SOL_SOCKET
, SO_NOSIGPIPE
,
212 (char *)&flag
, sizeof(flag
)) < 0) {
213 omapi_connection_dereference (&obj
, MDL
);
214 return ISC_R_UNEXPECTED
;
218 status
= (omapi_register_io_object
219 ((omapi_object_t
*)obj
,
220 0, omapi_connection_writefd
,
221 0, omapi_connection_connect
,
222 omapi_connection_reaper
));
223 if (status
!= ISC_R_SUCCESS
)
225 status
= omapi_connection_connect_internal ((omapi_object_t
*)
228 * inprogress is the same as success but used
229 * to indicate to the dispatch code that we should
230 * mark the socket as requiring more attention.
231 * Routines calling this function should handle
234 if (status
== ISC_R_INPROGRESS
) {
235 status
= ISC_R_SUCCESS
;
237 #if defined (TRACING)
239 omapi_connection_register (obj
, MDL
);
243 omapi_connection_dereference (&obj
, MDL
);
247 #if defined (TRACING)
248 omapi_array_t
*omapi_connections
;
250 OMAPI_ARRAY_TYPE(omapi_connection
, omapi_connection_object_t
)
252 void omapi_connection_trace_setup (void) {
253 trace_connect
= trace_type_register ("connect", (void *)0,
255 trace_connect_stop
, MDL
);
256 trace_disconnect
= trace_type_register ("disconnect", (void *)0,
257 trace_disconnect_input
,
258 trace_disconnect_stop
, MDL
);
261 void omapi_connection_register (omapi_connection_object_t
*obj
,
262 const char *file
, int line
)
267 int32_t connect_index
, listener_index
;
268 static int32_t index
;
270 if (!omapi_connections
) {
271 status
= omapi_connection_array_allocate (&omapi_connections
,
273 if (status
!= ISC_R_SUCCESS
)
277 status
= omapi_connection_array_extend (omapi_connections
, obj
,
278 (int *)0, file
, line
);
279 if (status
!= ISC_R_SUCCESS
) {
284 #if defined (TRACING)
285 if (trace_record ()) {
286 /* Connection registration packet:
289 int32_t listener_index [-1 means no listener]
290 u_int16_t remote_port
292 u_int32_t remote_addr
293 u_int32_t local_addr */
295 connect_index
= htonl (index
);
298 listener_index
= htonl (obj
-> listener
-> index
);
300 listener_index
= htonl (-1);
301 iov
[iov_count
].buf
= (char *)&connect_index
;
302 iov
[iov_count
++].len
= sizeof connect_index
;
303 iov
[iov_count
].buf
= (char *)&listener_index
;
304 iov
[iov_count
++].len
= sizeof listener_index
;
305 iov
[iov_count
].buf
= (char *)&obj
-> remote_addr
.sin_port
;
306 iov
[iov_count
++].len
= sizeof obj
-> remote_addr
.sin_port
;
307 iov
[iov_count
].buf
= (char *)&obj
-> local_addr
.sin_port
;
308 iov
[iov_count
++].len
= sizeof obj
-> local_addr
.sin_port
;
309 iov
[iov_count
].buf
= (char *)&obj
-> remote_addr
.sin_addr
;
310 iov
[iov_count
++].len
= sizeof obj
-> remote_addr
.sin_addr
;
311 iov
[iov_count
].buf
= (char *)&obj
-> local_addr
.sin_addr
;
312 iov
[iov_count
++].len
= sizeof obj
-> local_addr
.sin_addr
;
314 status
= trace_write_packet_iov (trace_connect
,
315 iov_count
, iov
, file
, line
);
320 static void trace_connect_input (trace_type_t
*ttype
,
321 unsigned length
, char *buf
)
323 struct sockaddr_in remote
, local
;
324 int32_t connect_index
, listener_index
;
326 omapi_connection_object_t
*obj
;
330 if (length
!= ((sizeof connect_index
) +
331 (sizeof remote
.sin_port
) +
332 (sizeof remote
.sin_addr
)) * 2) {
333 log_error ("Trace connect: invalid length %d", length
);
337 memset (&remote
, 0, sizeof remote
);
338 memset (&local
, 0, sizeof local
);
339 memcpy (&connect_index
, s
, sizeof connect_index
);
340 s
+= sizeof connect_index
;
341 memcpy (&listener_index
, s
, sizeof listener_index
);
342 s
+= sizeof listener_index
;
343 memcpy (&remote
.sin_port
, s
, sizeof remote
.sin_port
);
344 s
+= sizeof remote
.sin_port
;
345 memcpy (&local
.sin_port
, s
, sizeof local
.sin_port
);
346 s
+= sizeof local
.sin_port
;
347 memcpy (&remote
.sin_addr
, s
, sizeof remote
.sin_addr
);
348 s
+= sizeof remote
.sin_addr
;
349 memcpy (&local
.sin_addr
, s
, sizeof local
.sin_addr
);
350 s
+= sizeof local
.sin_addr
;
353 connect_index
= ntohl (connect_index
);
354 listener_index
= ntohl (listener_index
);
356 /* If this was a connect to a listener, then we just slap together
358 if (listener_index
!= -1) {
359 omapi_listener_object_t
*listener
;
360 listener
= (omapi_listener_object_t
*)0;
361 omapi_array_foreach_begin (trace_listeners
,
362 omapi_listener_object_t
, lp
) {
363 if (lp
-> address
.sin_port
== local
.sin_port
) {
364 omapi_listener_reference (&listener
, lp
, MDL
);
365 omapi_listener_dereference (&lp
, MDL
);
368 } omapi_array_foreach_end (trace_listeners
,
369 omapi_listener_object_t
, lp
);
371 log_error ("%s%ld, addr %s, port %d",
372 "Spurious traced listener connect - index ",
373 (long int)listener_index
,
374 inet_ntoa (local
.sin_addr
),
375 ntohs (local
.sin_port
));
378 obj
= (omapi_connection_object_t
*)0;
379 status
= omapi_listener_connect (&obj
, listener
, -1, &remote
);
380 if (status
!= ISC_R_SUCCESS
) {
381 log_error ("traced listener connect: %s",
382 isc_result_totext (status
));
385 omapi_connection_dereference (&obj
, MDL
);
386 omapi_listener_dereference (&listener
, MDL
);
390 /* Find the matching connect object, if there is one. */
391 omapi_array_foreach_begin (omapi_connections
,
392 omapi_connection_object_t
, lp
) {
393 for (i
= 0; (lp
->connect_list
&&
394 i
< lp
->connect_list
->count
); i
++) {
395 if (!memcmp (&remote
.sin_addr
,
396 &lp
->connect_list
->addresses
[i
].address
,
397 sizeof remote
.sin_addr
) &&
398 (ntohs (remote
.sin_port
) ==
399 lp
->connect_list
->addresses
[i
].port
)) {
400 lp
->state
= omapi_connection_connected
;
401 lp
->remote_addr
= remote
;
402 lp
->remote_addr
.sin_family
= AF_INET
;
403 omapi_addr_list_dereference(&lp
->connect_list
, MDL
);
404 lp
->index
= connect_index
;
405 status
= omapi_signal_in((omapi_object_t
*)lp
,
407 omapi_connection_dereference (&lp
, MDL
);
411 } omapi_array_foreach_end (omapi_connections
,
412 omapi_connection_object_t
, lp
);
414 log_error ("Spurious traced connect - index %ld, addr %s, port %d",
415 (long int)connect_index
, inet_ntoa (remote
.sin_addr
),
416 ntohs (remote
.sin_port
));
420 static void trace_connect_stop (trace_type_t
*ttype
) { }
422 static void trace_disconnect_input (trace_type_t
*ttype
,
423 unsigned length
, char *buf
)
426 if (length
!= sizeof *index
) {
427 log_error ("trace disconnect: wrong length %d", length
);
431 index
= (int32_t *)buf
;
433 omapi_array_foreach_begin (omapi_connections
,
434 omapi_connection_object_t
, lp
) {
435 if (lp
-> index
== ntohl (*index
)) {
436 omapi_disconnect ((omapi_object_t
*)lp
, 1);
437 omapi_connection_dereference (&lp
, MDL
);
440 } omapi_array_foreach_end (omapi_connections
,
441 omapi_connection_object_t
, lp
);
443 log_error ("trace disconnect: no connection matching index %ld",
444 (long int)ntohl (*index
));
447 static void trace_disconnect_stop (trace_type_t
*ttype
) { }
450 /* Disconnect a connection object from the remote end. If force is nonzero,
451 close the connection immediately. Otherwise, shut down the receiving end
452 but allow any unsent data to be sent before actually closing the socket. */
454 isc_result_t
omapi_disconnect (omapi_object_t
*h
,
457 omapi_connection_object_t
*c
;
459 #ifdef DEBUG_PROTOCOL
460 log_debug ("omapi_disconnect(%s)", force
? "force" : "");
463 c
= (omapi_connection_object_t
*)h
;
464 if (c
-> type
!= omapi_type_connection
)
465 return DHCP_R_INVALIDARG
;
467 #if defined (TRACING)
468 if (trace_record ()) {
472 index
= htonl (c
-> index
);
473 status
= trace_write_packet (trace_disconnect
,
474 sizeof index
, (char *)&index
,
476 if (status
!= ISC_R_SUCCESS
) {
478 log_error ("trace_write_packet: %s",
479 isc_result_totext (status
));
482 if (!trace_playback ()) {
485 /* If we're already disconnecting, we don't have to do
487 if (c
-> state
== omapi_connection_disconnecting
)
488 return ISC_R_SUCCESS
;
490 /* Try to shut down the socket - this sends a FIN to
491 the remote end, so that it won't send us any more
492 data. If the shutdown succeeds, and we still
493 have bytes left to write, defer closing the socket
494 until that's done. */
495 if (!shutdown (c
-> socket
, SHUT_RD
)) {
496 if (c
-> out_bytes
> 0) {
498 omapi_connection_disconnecting
;
499 return ISC_R_SUCCESS
;
504 #if defined (TRACING)
507 c
-> state
= omapi_connection_closed
;
511 * Disconnecting from the I/O object seems incorrect as it doesn't
512 * cause the I/O object to be cleaned and released. Previous to
513 * using the isc socket library this wouldn't have caused a problem
514 * with the socket library we would have a reference to a closed
515 * socket. Instead we now do an unregister to properly free the
519 /* Disconnect from I/O object, if any. */
521 if (h
-> outer
-> inner
)
522 omapi_object_dereference (&h
-> outer
-> inner
, MDL
);
523 omapi_object_dereference (&h
-> outer
, MDL
);
527 omapi_unregister_io_object(h
);
531 /* If whatever created us registered a signal handler, send it
532 a disconnect signal. */
533 omapi_signal (h
, "disconnect", h
);
535 /* Disconnect from protocol object, if any. */
536 if (h
->inner
!= NULL
) {
537 if (h
->inner
->outer
!= NULL
) {
538 omapi_object_dereference(&h
->inner
->outer
, MDL
);
540 omapi_object_dereference(&h
->inner
, MDL
);
543 /* XXX: the code to free buffers should be in the dereference
544 function, but there is no special-purpose function to
545 dereference connections, so these just get leaked */
546 /* Free any buffers */
547 if (c
->inbufs
!= NULL
) {
548 omapi_buffer_dereference(&c
->inbufs
, MDL
);
551 if (c
->outbufs
!= NULL
) {
552 omapi_buffer_dereference(&c
->outbufs
, MDL
);
556 return ISC_R_SUCCESS
;
559 isc_result_t
omapi_connection_require (omapi_object_t
*h
, unsigned bytes
)
561 omapi_connection_object_t
*c
;
563 if (h
-> type
!= omapi_type_connection
)
564 return DHCP_R_INVALIDARG
;
565 c
= (omapi_connection_object_t
*)h
;
567 c
-> bytes_needed
= bytes
;
568 if (c
-> bytes_needed
<= c
-> in_bytes
) {
569 return ISC_R_SUCCESS
;
571 return DHCP_R_NOTYET
;
574 /* Return the socket on which the dispatcher should wait for readiness
575 to read, for a connection object. */
576 int omapi_connection_readfd (omapi_object_t
*h
)
578 omapi_connection_object_t
*c
;
579 if (h
-> type
!= omapi_type_connection
)
581 c
= (omapi_connection_object_t
*)h
;
582 if (c
-> state
!= omapi_connection_connected
)
588 * Return the socket on which the dispatcher should wait for readiness
589 * to write, for a connection object. When bytes are buffered we should
590 * also poke the dispatcher to tell it to start or re-start watching the
593 int omapi_connection_writefd (omapi_object_t
*h
)
595 omapi_connection_object_t
*c
;
596 if (h
-> type
!= omapi_type_connection
)
598 c
= (omapi_connection_object_t
*)h
;
602 isc_result_t
omapi_connection_connect (omapi_object_t
*h
)
607 * We use the INPROGRESS status to indicate that
608 * we want more from the socket. In this case we
609 * have now connected and are trying to write to
610 * the socket for the first time. For the signaling
611 * code this is the same as a SUCCESS so we don't
612 * pass it on as a signal.
614 status
= omapi_connection_connect_internal (h
);
615 if (status
== ISC_R_INPROGRESS
)
616 return ISC_R_INPROGRESS
;
618 if (status
!= ISC_R_SUCCESS
)
619 omapi_signal (h
, "status", status
);
621 return ISC_R_SUCCESS
;
624 static isc_result_t
omapi_connection_connect_internal (omapi_object_t
*h
)
627 omapi_connection_object_t
*c
;
631 if (h
-> type
!= omapi_type_connection
)
632 return DHCP_R_INVALIDARG
;
633 c
= (omapi_connection_object_t
*)h
;
635 if (c
-> state
== omapi_connection_connecting
) {
637 if (getsockopt (c
-> socket
, SOL_SOCKET
, SO_ERROR
,
638 (char *)&error
, &sl
) < 0) {
639 omapi_disconnect (h
, 1);
640 return ISC_R_SUCCESS
;
643 c
-> state
= omapi_connection_connected
;
645 if (c
-> state
== omapi_connection_connecting
||
646 c
-> state
== omapi_connection_unconnected
) {
647 if (c
-> cptr
>= c
-> connect_list
-> count
) {
650 status
= ISC_R_CONNREFUSED
;
653 status
= ISC_R_NETUNREACH
;
656 status
= uerr2isc (error
);
659 omapi_disconnect (h
, 1);
663 if (c
-> connect_list
-> addresses
[c
-> cptr
].addrtype
!=
665 omapi_disconnect (h
, 1);
666 return DHCP_R_INVALIDARG
;
669 memcpy (&c
-> remote_addr
.sin_addr
,
670 &c
-> connect_list
-> addresses
[c
-> cptr
].address
,
671 sizeof c
-> remote_addr
.sin_addr
);
672 c
-> remote_addr
.sin_family
= AF_INET
;
673 c
-> remote_addr
.sin_port
=
674 htons (c
-> connect_list
-> addresses
[c
-> cptr
].port
);
675 #if defined (HAVE_SA_LEN)
676 c
-> remote_addr
.sin_len
= sizeof c
-> remote_addr
;
678 memset (&c
-> remote_addr
.sin_zero
, 0,
679 sizeof c
-> remote_addr
.sin_zero
);
682 error
= connect (c
-> socket
,
683 (struct sockaddr
*)&c
-> remote_addr
,
684 sizeof c
-> remote_addr
);
687 if (error
!= EINPROGRESS
) {
688 omapi_disconnect (h
, 1);
691 status
= ISC_R_CONNREFUSED
;
694 status
= ISC_R_NETUNREACH
;
697 status
= uerr2isc (error
);
702 c
-> state
= omapi_connection_connecting
;
703 return DHCP_R_INCOMPLETE
;
705 c
-> state
= omapi_connection_connected
;
708 /* I don't know why this would fail, so I'm tempted not to test
710 sl
= sizeof (c
-> local_addr
);
711 if (getsockname (c
-> socket
,
712 (struct sockaddr
*)&c
-> local_addr
, &sl
) < 0) {
715 /* Reregister with the I/O object. If we don't already have an
716 I/O object this turns into a register call, otherwise we simply
717 modify the pointers in the I/O object. */
719 status
= omapi_reregister_io_object (h
,
720 omapi_connection_readfd
,
721 omapi_connection_writefd
,
722 omapi_connection_reader
,
723 omapi_connection_writer
,
724 omapi_connection_reaper
);
726 if (status
!= ISC_R_SUCCESS
) {
727 omapi_disconnect (h
, 1);
731 omapi_signal_in (h
, "connect");
732 omapi_addr_list_dereference (&c
-> connect_list
, MDL
);
733 return ISC_R_INPROGRESS
;
736 /* Reaper function for connection - if the connection is completely closed,
737 reap it. If it's in the disconnecting state, there were bytes left
738 to write when the user closed it, so if there are now no bytes left to
739 write, we can close it. */
740 isc_result_t
omapi_connection_reaper (omapi_object_t
*h
)
742 omapi_connection_object_t
*c
;
744 if (h
-> type
!= omapi_type_connection
)
745 return DHCP_R_INVALIDARG
;
747 c
= (omapi_connection_object_t
*)h
;
748 if (c
-> state
== omapi_connection_disconnecting
&&
749 c
-> out_bytes
== 0) {
750 #ifdef DEBUG_PROTOCOL
751 log_debug ("omapi_connection_reaper(): disconnect");
753 omapi_disconnect (h
, 1);
755 if (c
-> state
== omapi_connection_closed
) {
756 #ifdef DEBUG_PROTOCOL
757 log_debug ("omapi_connection_reaper(): closed");
759 return ISC_R_NOTCONNECTED
;
761 return ISC_R_SUCCESS
;
764 static isc_result_t
make_dst_key (dst_key_t
**dst_key
, omapi_object_t
*a
) {
765 omapi_value_t
*name
= (omapi_value_t
*)0;
766 omapi_value_t
*algorithm
= (omapi_value_t
*)0;
767 omapi_value_t
*key
= (omapi_value_t
*)0;
768 char *name_str
= NULL
;
769 isc_result_t status
= ISC_R_SUCCESS
;
771 if (status
== ISC_R_SUCCESS
)
772 status
= omapi_get_value_str
773 (a
, (omapi_object_t
*)0, "name", &name
);
775 if (status
== ISC_R_SUCCESS
)
776 status
= omapi_get_value_str
777 (a
, (omapi_object_t
*)0, "algorithm", &algorithm
);
779 if (status
== ISC_R_SUCCESS
)
780 status
= omapi_get_value_str
781 (a
, (omapi_object_t
*)0, "key", &key
);
783 if (status
== ISC_R_SUCCESS
) {
784 if ((algorithm
->value
->type
!= omapi_datatype_data
&&
785 algorithm
->value
->type
!= omapi_datatype_string
) ||
786 strncasecmp((char *)algorithm
->value
->u
.buffer
.value
,
787 NS_TSIG_ALG_HMAC_MD5
".",
788 algorithm
->value
->u
.buffer
.len
) != 0) {
789 status
= DHCP_R_INVALIDARG
;
793 if (status
== ISC_R_SUCCESS
) {
794 name_str
= dmalloc (name
-> value
-> u
.buffer
.len
+ 1, MDL
);
796 status
= ISC_R_NOMEMORY
;
799 if (status
== ISC_R_SUCCESS
) {
801 name
-> value
-> u
.buffer
.value
,
802 name
-> value
-> u
.buffer
.len
);
803 name_str
[name
-> value
-> u
.buffer
.len
] = 0;
805 status
= isclib_make_dst_key(name_str
,
807 key
->value
->u
.buffer
.value
,
808 key
->value
->u
.buffer
.len
,
811 if (*dst_key
== NULL
)
812 status
= ISC_R_NOMEMORY
;
816 dfree (name_str
, MDL
);
818 omapi_value_dereference (&key
, MDL
);
820 omapi_value_dereference (&algorithm
, MDL
);
822 omapi_value_dereference (&name
, MDL
);
827 isc_result_t
omapi_connection_sign_data (int mode
,
830 const unsigned char *data
,
832 omapi_typed_data_t
**result
)
834 omapi_typed_data_t
*td
= (omapi_typed_data_t
*)0;
836 dst_context_t
**dctx
= (dst_context_t
**)context
;
838 /* Create the context for the dst module */
839 if (mode
& SIG_MODE_INIT
) {
840 status
= dst_context_create(key
, dhcp_gbl_ctx
.mctx
, dctx
);
841 if (status
!= ISC_R_SUCCESS
) {
846 /* If we have any data add it to the context */
849 region
.base
= (unsigned char *)data
;
851 dst_context_adddata(*dctx
, ®ion
);
854 /* Finish the signature and clean up the context */
855 if (mode
& SIG_MODE_FINAL
) {
856 unsigned int sigsize
;
859 status
= dst_key_sigsize(key
, &sigsize
);
860 if (status
!= ISC_R_SUCCESS
) {
864 status
= omapi_typed_data_new (MDL
, &td
,
867 if (status
!= ISC_R_SUCCESS
) {
871 isc_buffer_init(&sigbuf
, td
->u
.buffer
.value
, td
->u
.buffer
.len
);
872 status
= dst_context_sign(*dctx
, &sigbuf
);
873 if (status
!= ISC_R_SUCCESS
) {
878 omapi_typed_data_reference (result
, td
, MDL
);
882 /* We are done with the context and the td. On success
883 * the td is now referenced from result, on failure we
884 * don't need it any more */
886 omapi_typed_data_dereference (&td
, MDL
);
888 dst_context_destroy(dctx
);
892 return ISC_R_SUCCESS
;
895 isc_result_t
omapi_connection_output_auth_length (omapi_object_t
*h
,
898 omapi_connection_object_t
*c
;
900 if (h
->type
!= omapi_type_connection
)
901 return DHCP_R_INVALIDARG
;
902 c
= (omapi_connection_object_t
*)h
;
904 if (c
->out_key
== NULL
)
905 return ISC_R_NOTFOUND
;
907 return(dst_key_sigsize(c
->out_key
, l
));
910 isc_result_t
omapi_connection_set_value (omapi_object_t
*h
,
912 omapi_data_string_t
*name
,
913 omapi_typed_data_t
*value
)
915 omapi_connection_object_t
*c
;
918 if (h
-> type
!= omapi_type_connection
)
919 return DHCP_R_INVALIDARG
;
920 c
= (omapi_connection_object_t
*)h
;
922 if (omapi_ds_strcmp (name
, "input-authenticator") == 0) {
923 if (value
&& value
-> type
!= omapi_datatype_object
)
924 return DHCP_R_INVALIDARG
;
926 if (c
-> in_context
) {
927 omapi_connection_sign_data (SIG_MODE_FINAL
,
931 (omapi_typed_data_t
**) 0);
934 if (c
->in_key
!= NULL
) {
935 dst_key_free(&c
->in_key
);
939 status
= make_dst_key (&c
-> in_key
,
941 if (status
!= ISC_R_SUCCESS
)
945 return ISC_R_SUCCESS
;
947 else if (omapi_ds_strcmp (name
, "output-authenticator") == 0) {
948 if (value
&& value
-> type
!= omapi_datatype_object
)
949 return DHCP_R_INVALIDARG
;
951 if (c
-> out_context
) {
952 omapi_connection_sign_data (SIG_MODE_FINAL
,
956 (omapi_typed_data_t
**) 0);
959 if (c
->out_key
!= NULL
) {
960 dst_key_free(&c
->out_key
);
964 status
= make_dst_key (&c
-> out_key
,
966 if (status
!= ISC_R_SUCCESS
)
970 return ISC_R_SUCCESS
;
973 if (h
-> inner
&& h
-> inner
-> type
-> set_value
)
974 return (*(h
-> inner
-> type
-> set_value
))
975 (h
-> inner
, id
, name
, value
);
976 return ISC_R_NOTFOUND
;
979 isc_result_t
omapi_connection_get_value (omapi_object_t
*h
,
981 omapi_data_string_t
*name
,
982 omapi_value_t
**value
)
984 omapi_connection_object_t
*c
;
985 omapi_typed_data_t
*td
= (omapi_typed_data_t
*)0;
987 unsigned int sigsize
;
989 if (h
-> type
!= omapi_type_connection
)
990 return DHCP_R_INVALIDARG
;
991 c
= (omapi_connection_object_t
*)h
;
993 if (omapi_ds_strcmp (name
, "input-signature") == 0) {
994 if (!c
-> in_key
|| !c
-> in_context
)
995 return ISC_R_NOTFOUND
;
997 status
= omapi_connection_sign_data (SIG_MODE_FINAL
,
1001 if (status
!= ISC_R_SUCCESS
)
1004 status
= omapi_make_value (value
, name
, td
, MDL
);
1005 omapi_typed_data_dereference (&td
, MDL
);
1008 } else if (omapi_ds_strcmp (name
, "input-signature-size") == 0) {
1009 if (c
->in_key
== NULL
)
1010 return ISC_R_NOTFOUND
;
1012 status
= dst_key_sigsize(c
->in_key
, &sigsize
);
1013 if (status
!= ISC_R_SUCCESS
) {
1017 return omapi_make_int_value(value
, name
, sigsize
, MDL
);
1019 } else if (omapi_ds_strcmp (name
, "output-signature") == 0) {
1020 if (!c
-> out_key
|| !c
-> out_context
)
1021 return ISC_R_NOTFOUND
;
1023 status
= omapi_connection_sign_data (SIG_MODE_FINAL
,
1027 if (status
!= ISC_R_SUCCESS
)
1030 status
= omapi_make_value (value
, name
, td
, MDL
);
1031 omapi_typed_data_dereference (&td
, MDL
);
1034 } else if (omapi_ds_strcmp (name
, "output-signature-size") == 0) {
1035 if (c
->out_key
== NULL
)
1036 return ISC_R_NOTFOUND
;
1039 status
= dst_key_sigsize(c
->out_key
, &sigsize
);
1040 if (status
!= ISC_R_SUCCESS
) {
1044 return omapi_make_int_value(value
, name
, sigsize
, MDL
);
1047 if (h
-> inner
&& h
-> inner
-> type
-> get_value
)
1048 return (*(h
-> inner
-> type
-> get_value
))
1049 (h
-> inner
, id
, name
, value
);
1050 return ISC_R_NOTFOUND
;
1053 isc_result_t
omapi_connection_destroy (omapi_object_t
*h
,
1054 const char *file
, int line
)
1056 omapi_connection_object_t
*c
;
1058 #ifdef DEBUG_PROTOCOL
1059 log_debug ("omapi_connection_destroy()");
1062 if (h
-> type
!= omapi_type_connection
)
1063 return ISC_R_UNEXPECTED
;
1064 c
= (omapi_connection_object_t
*)(h
);
1065 if (c
-> state
== omapi_connection_connected
)
1066 omapi_disconnect (h
, 1);
1068 omapi_listener_dereference (&c
-> listener
, file
, line
);
1069 if (c
-> connect_list
)
1070 omapi_addr_list_dereference (&c
-> connect_list
, file
, line
);
1071 return ISC_R_SUCCESS
;
1074 isc_result_t
omapi_connection_signal_handler (omapi_object_t
*h
,
1075 const char *name
, va_list ap
)
1077 if (h
-> type
!= omapi_type_connection
)
1078 return DHCP_R_INVALIDARG
;
1080 #ifdef DEBUG_PROTOCOL
1081 log_debug ("omapi_connection_signal_handler(%s)", name
);
1084 if (h
-> inner
&& h
-> inner
-> type
-> signal_handler
)
1085 return (*(h
-> inner
-> type
-> signal_handler
)) (h
-> inner
,
1087 return ISC_R_NOTFOUND
;
1090 /* Write all the published values associated with the object through the
1091 specified connection. */
1093 isc_result_t
omapi_connection_stuff_values (omapi_object_t
*c
,
1097 if (m
-> type
!= omapi_type_connection
)
1098 return DHCP_R_INVALIDARG
;
1100 if (m
-> inner
&& m
-> inner
-> type
-> stuff_values
)
1101 return (*(m
-> inner
-> type
-> stuff_values
)) (c
, id
,
1103 return ISC_R_SUCCESS
;