revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / omapip / connection.c
blob2fa40f16312ed4bb2532576af926fcfd40ca3882
1 /* connection.c
3 Subroutines for dealing with connections. */
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1999-2003 by Internet Software Consortium
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.
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.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
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''.
35 #include <omapip/omapip_p.h>
36 #include <arpa/inet.h>
37 #include <arpa/nameser.h>
40 #if defined (TRACING)
41 static void trace_connect_input (trace_type_t *, unsigned, char *);
42 static void trace_connect_stop (trace_type_t *);
43 static void trace_disconnect_input (trace_type_t *, unsigned, char *);
44 static void trace_disconnect_stop (trace_type_t *);
45 trace_type_t *trace_connect;
46 trace_type_t *trace_disconnect;
47 extern omapi_array_t *trace_listeners;
48 #endif
49 static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
51 OMAPI_OBJECT_ALLOC (omapi_connection,
52 omapi_connection_object_t, omapi_type_connection)
54 isc_result_t omapi_connect (omapi_object_t *c,
55 const char *server_name,
56 unsigned port)
58 struct hostent *he;
59 unsigned i, hix;
60 omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
61 struct in_addr foo;
62 isc_result_t status;
64 #ifdef DEBUG_PROTOCOL
65 log_debug ("omapi_connect(%s, port=%d)", server_name, port);
66 #endif
68 if (!inet_aton (server_name, &foo)) {
69 /* If we didn't get a numeric address, try for a domain
70 name. It's okay for this call to block. */
71 he = gethostbyname (server_name);
72 if (!he)
73 return ISC_R_HOSTUNKNOWN;
74 for (i = 0; he -> h_addr_list [i]; i++)
76 if (i == 0)
77 return ISC_R_HOSTUNKNOWN;
78 hix = i;
80 status = omapi_addr_list_new (&addrs, hix, MDL);
81 if (status != ISC_R_SUCCESS)
82 return status;
83 for (i = 0; i < hix; i++) {
84 addrs -> addresses [i].addrtype = he -> h_addrtype;
85 addrs -> addresses [i].addrlen = he -> h_length;
86 memcpy (addrs -> addresses [i].address,
87 he -> h_addr_list [i],
88 (unsigned)he -> h_length);
89 addrs -> addresses [i].port = port;
91 } else {
92 status = omapi_addr_list_new (&addrs, 1, MDL);
93 if (status != ISC_R_SUCCESS)
94 return status;
95 addrs -> addresses [0].addrtype = AF_INET;
96 addrs -> addresses [0].addrlen = sizeof foo;
97 memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
98 addrs -> addresses [0].port = port;
99 hix = 1;
101 status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
102 omapi_addr_list_dereference (&addrs, MDL);
103 return status;
106 isc_result_t omapi_connect_list (omapi_object_t *c,
107 omapi_addr_list_t *remote_addrs,
108 omapi_addr_t *local_addr)
110 isc_result_t status;
111 omapi_connection_object_t *obj;
112 int flag;
113 struct sockaddr_in local_sin;
114 #if defined (TRACING)
115 // trace_addr_t *addrs;
116 // u_int16_t naddrs;
117 #endif
119 obj = (omapi_connection_object_t *)0;
120 status = omapi_connection_allocate (&obj, MDL);
121 if (status != ISC_R_SUCCESS)
122 return status;
124 status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
125 MDL);
126 if (status != ISC_R_SUCCESS) {
127 omapi_connection_dereference (&obj, MDL);
128 return status;
130 status = omapi_object_reference (&obj -> inner, c, MDL);
131 if (status != ISC_R_SUCCESS) {
132 omapi_connection_dereference (&obj, MDL);
133 return status;
136 /* Store the address list on the object. */
137 omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
138 obj -> cptr = 0;
139 obj -> state = omapi_connection_unconnected;
141 #if defined (TRACING)
142 /* If we're playing back, don't actually try to connect - just leave
143 the object available for a subsequent connect or disconnect. */
144 if (!trace_playback ()) {
145 #endif
146 /* Create a socket on which to communicate. */
147 obj -> socket =
148 socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
149 if (obj -> socket < 0) {
150 omapi_connection_dereference (&obj, MDL);
151 if (errno == EMFILE || errno == ENFILE
152 || errno == ENOBUFS)
153 return ISC_R_NORESOURCES;
154 return ISC_R_UNEXPECTED;
157 /* Set up the local address, if any. */
158 if (local_addr) {
159 /* Only do TCPv4 so far. */
160 if (local_addr -> addrtype != AF_INET) {
161 omapi_connection_dereference (&obj, MDL);
162 return ISC_R_INVALIDARG;
164 local_sin.sin_port = htons (local_addr -> port);
165 memcpy (&local_sin.sin_addr,
166 local_addr -> address,
167 local_addr -> addrlen);
168 #if defined (HAVE_SA_LEN)
169 local_sin.sin_len = sizeof local_addr;
170 #endif
171 local_sin.sin_family = AF_INET;
172 memset (&local_sin.sin_zero, 0,
173 sizeof local_sin.sin_zero);
175 if (bind (obj -> socket, (struct sockaddr *)&local_sin,
176 sizeof local_sin) < 0) {
177 omapi_object_dereference ((omapi_object_t **)
178 &obj, MDL);
179 if (errno == EADDRINUSE)
180 return ISC_R_ADDRINUSE;
181 if (errno == EADDRNOTAVAIL)
182 return ISC_R_ADDRNOTAVAIL;
183 if (errno == EACCES)
184 return ISC_R_NOPERM;
185 return ISC_R_UNEXPECTED;
187 obj -> local_addr = local_sin;
190 #if defined (HAVE_SETFD)
191 if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
192 close (obj -> socket);
193 omapi_connection_dereference (&obj, MDL);
194 return ISC_R_UNEXPECTED;
196 #endif
198 /* Set the SO_REUSEADDR flag (this should not fail). */
199 flag = 1;
200 if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
201 (char *)&flag, sizeof flag) < 0) {
202 omapi_connection_dereference (&obj, MDL);
203 return ISC_R_UNEXPECTED;
206 /* Set the file to nonblocking mode. */
207 #ifdef SOCKET_IS_NOT_A_FILE
208 if (IoctlSocket (obj -> socket, FIONBIO, (char *)&flag) < 0)
209 #else
210 if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0)
211 #endif
213 omapi_connection_dereference (&obj, MDL);
214 return ISC_R_UNEXPECTED;
217 status = (omapi_register_io_object
218 ((omapi_object_t *)obj,
219 0, omapi_connection_writefd,
220 0, omapi_connection_connect,
221 omapi_connection_reaper));
222 if (status != ISC_R_SUCCESS)
223 goto out;
224 status = omapi_connection_connect_internal ((omapi_object_t *)
225 obj);
226 #if defined (TRACING)
228 omapi_connection_register (obj, MDL);
229 #endif
231 out:
232 omapi_connection_dereference (&obj, MDL);
233 return status;
236 #if defined (TRACING)
237 omapi_array_t *omapi_connections;
239 OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t)
241 void omapi_connection_trace_setup (void) {
242 trace_connect = trace_type_register ("connect", (void *)0,
243 trace_connect_input,
244 trace_connect_stop, MDL);
245 trace_disconnect = trace_type_register ("disconnect", (void *)0,
246 trace_disconnect_input,
247 trace_disconnect_stop, MDL);
250 void omapi_connection_register (omapi_connection_object_t *obj,
251 const char *file, int line)
253 isc_result_t status;
254 trace_iov_t iov [6];
255 int iov_count = 0;
256 int32_t connect_index, listener_index;
257 static int32_t index;
259 if (!omapi_connections) {
260 status = omapi_connection_array_allocate (&omapi_connections,
261 file, line);
262 if (status != ISC_R_SUCCESS)
263 return;
266 status = omapi_connection_array_extend (omapi_connections, obj,
267 (int *)0, file, line);
268 if (status != ISC_R_SUCCESS) {
269 obj -> index = -1;
270 return;
273 #if defined (TRACING)
274 if (trace_record ()) {
275 /* Connection registration packet:
277 int32_t index
278 int32_t listener_index [-1 means no listener]
279 u_int16_t remote_port
280 u_int16_t local_port
281 u_int32_t remote_addr
282 u_int32_t local_addr */
284 connect_index = htonl (index);
285 index++;
286 if (obj -> listener)
287 listener_index = htonl (obj -> listener -> index);
288 else
289 listener_index = htonl (-1);
290 iov [iov_count].buf = (char *)&connect_index;
291 iov [iov_count++].len = sizeof connect_index;
292 iov [iov_count].buf = (char *)&listener_index;
293 iov [iov_count++].len = sizeof listener_index;
294 iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
295 iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
296 iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
297 iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
298 iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
299 iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
300 iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
301 iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
303 status = trace_write_packet_iov (trace_connect,
304 iov_count, iov, file, line);
306 #endif
309 static void trace_connect_input (trace_type_t *ttype,
310 unsigned length, char *buf)
312 struct sockaddr_in remote, local;
313 int32_t connect_index, listener_index;
314 char *s = buf;
315 omapi_connection_object_t *obj;
316 isc_result_t status;
317 int i;
319 if (length != ((sizeof connect_index) +
320 (sizeof remote.sin_port) +
321 (sizeof remote.sin_addr)) * 2) {
322 log_error ("Trace connect: invalid length %d", length);
323 return;
326 memset (&remote, 0, sizeof remote);
327 memset (&local, 0, sizeof local);
328 memcpy (&connect_index, s, sizeof connect_index);
329 s += sizeof connect_index;
330 memcpy (&listener_index, s, sizeof listener_index);
331 s += sizeof listener_index;
332 memcpy (&remote.sin_port, s, sizeof remote.sin_port);
333 s += sizeof remote.sin_port;
334 memcpy (&local.sin_port, s, sizeof local.sin_port);
335 s += sizeof local.sin_port;
336 memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
337 s += sizeof remote.sin_addr;
338 memcpy (&local.sin_addr, s, sizeof local.sin_addr);
339 s += sizeof local.sin_addr;
341 connect_index = ntohl (connect_index);
342 listener_index = ntohl (listener_index);
344 /* If this was a connect to a listener, then we just slap together
345 a new connection. */
346 if (listener_index != -1) {
347 omapi_listener_object_t *listener;
348 listener = (omapi_listener_object_t *)0;
349 omapi_array_foreach_begin (trace_listeners,
350 omapi_listener_object_t, lp) {
351 if (lp -> address.sin_port == local.sin_port) {
352 omapi_listener_reference (&listener, lp, MDL);
353 omapi_listener_dereference (&lp, MDL);
354 break;
356 } omapi_array_foreach_end (trace_listeners,
357 omapi_listener_object_t, lp);
358 if (!listener) {
359 log_error ("%s%ld, addr %s, port %d",
360 "Spurious traced listener connect - index ",
361 (long int)listener_index,
362 inet_ntoa (local.sin_addr),
363 ntohs (local.sin_port));
364 return;
366 obj = (omapi_connection_object_t *)0;
367 status = omapi_listener_connect (&obj, listener, -1, &remote);
368 if (status != ISC_R_SUCCESS) {
369 log_error ("traced listener connect: %s",
370 isc_result_totext (status));
372 if (obj)
373 omapi_connection_dereference (&obj, MDL);
374 omapi_listener_dereference (&listener, MDL);
375 return;
378 /* Find the matching connect object, if there is one. */
379 omapi_array_foreach_begin (omapi_connections,
380 omapi_connection_object_t, lp) {
381 for (i = 0; (lp -> connect_list &&
382 i < lp -> connect_list -> count); i++) {
383 if (!memcmp (&remote.sin_addr,
384 &lp -> connect_list -> addresses [i].address,
385 sizeof remote.sin_addr) &&
386 (ntohs (remote.sin_port) ==
387 lp -> connect_list -> addresses [i].port))
388 lp -> state = omapi_connection_connected;
389 lp -> remote_addr = remote;
390 lp -> remote_addr.sin_family = AF_INET;
391 #if defined (HAVE_SIN_LEN)
392 lp -> remote_addr.sin_len = sizeof remote;
393 #endif
394 omapi_addr_list_dereference (&lp -> connect_list, MDL);
395 lp -> index = connect_index;
396 status = omapi_signal_in ((omapi_object_t *)lp,
397 "connect");
398 omapi_connection_dereference (&lp, MDL);
399 return;
401 } omapi_array_foreach_end (omapi_connections,
402 omapi_connection_object_t, lp);
404 log_error ("Spurious traced connect - index %ld, addr %s, port %d",
405 (long int)connect_index, inet_ntoa (remote.sin_addr),
406 ntohs (remote.sin_port));
407 return;
410 static void trace_connect_stop (trace_type_t *ttype) { }
412 static void trace_disconnect_input (trace_type_t *ttype,
413 unsigned length, char *buf)
415 int32_t *index;
416 if (length != sizeof *index) {
417 log_error ("trace disconnect: wrong length %d", length);
418 return;
421 index = (int32_t *)buf;
423 omapi_array_foreach_begin (omapi_connections,
424 omapi_connection_object_t, lp) {
425 if (lp -> index == ntohl (*index)) {
426 omapi_disconnect ((omapi_object_t *)lp, 1);
427 omapi_connection_dereference (&lp, MDL);
428 return;
430 } omapi_array_foreach_end (omapi_connections,
431 omapi_connection_object_t, lp);
433 log_error ("trace disconnect: no connection matching index %ld",
434 (long int)ntohl (*index));
437 static void trace_disconnect_stop (trace_type_t *ttype) { }
438 #endif
440 /* Disconnect a connection object from the remote end. If force is nonzero,
441 close the connection immediately. Otherwise, shut down the receiving end
442 but allow any unsent data to be sent before actually closing the socket. */
444 isc_result_t omapi_disconnect (omapi_object_t *h,
445 int force)
447 omapi_connection_object_t *c;
448 isc_result_t status;
450 #ifdef DEBUG_PROTOCOL
451 log_debug ("omapi_disconnect(%s)", force ? "force" : "");
452 #endif
454 c = (omapi_connection_object_t *)h;
455 if (c -> type != omapi_type_connection)
456 return ISC_R_INVALIDARG;
458 #if defined (TRACING)
459 if (trace_record ()) {
460 int32_t index;
462 index = htonl (c -> index);
463 status = trace_write_packet (trace_disconnect,
464 sizeof index, (char *)&index,
465 MDL);
466 if (status != ISC_R_SUCCESS) {
467 trace_stop ();
468 log_error ("trace_write_packet: %s",
469 isc_result_totext (status));
472 if (!trace_playback ()) {
473 #endif
474 if (!force) {
475 /* If we're already disconnecting, we don't have to do
476 anything. */
477 if (c -> state == omapi_connection_disconnecting)
478 return ISC_R_SUCCESS;
480 /* Try to shut down the socket - this sends a FIN to
481 the remote end, so that it won't send us any more
482 data. If the shutdown succeeds, and we still
483 have bytes left to write, defer closing the socket
484 until that's done. */
485 if (!shutdown (c -> socket, SHUT_RD)) {
486 if (c -> out_bytes > 0) {
487 c -> state =
488 omapi_connection_disconnecting;
489 return ISC_R_SUCCESS;
493 #ifdef SOCKET_IS_NOT_A_FILE
494 CloseSocket (c -> socket);
495 #else
496 close (c -> socket);
497 #endif
498 #if defined (TRACING)
500 #endif
501 c -> state = omapi_connection_closed;
503 /* Disconnect from I/O object, if any. */
504 if (h -> outer) {
505 if (h -> outer -> inner)
506 omapi_object_dereference (&h -> outer -> inner, MDL);
507 omapi_object_dereference (&h -> outer, MDL);
510 /* If whatever created us registered a signal handler, send it
511 a disconnect signal. */
512 omapi_signal (h, "disconnect", h);
513 return ISC_R_SUCCESS;
516 isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
518 omapi_connection_object_t *c;
520 if (h -> type != omapi_type_connection)
521 return ISC_R_INVALIDARG;
522 c = (omapi_connection_object_t *)h;
524 c -> bytes_needed = bytes;
525 if (c -> bytes_needed <= c -> in_bytes) {
526 return ISC_R_SUCCESS;
528 return ISC_R_NOTYET;
531 /* Return the socket on which the dispatcher should wait for readiness
532 to read, for a connection object. If we already have more bytes than
533 we need to do the next thing, and we have at least a single full input
534 buffer, then don't indicate that we're ready to read. */
535 int omapi_connection_readfd (omapi_object_t *h)
537 omapi_connection_object_t *c;
538 if (h -> type != omapi_type_connection)
539 return -1;
540 c = (omapi_connection_object_t *)h;
541 if (c -> state != omapi_connection_connected)
542 return -1;
543 if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 &&
544 c -> in_bytes > c -> bytes_needed)
545 return -1;
546 return c -> socket;
549 /* Return the socket on which the dispatcher should wait for readiness
550 to write, for a connection object. If there are no bytes buffered
551 for writing, then don't indicate that we're ready to write. */
552 int omapi_connection_writefd (omapi_object_t *h)
554 omapi_connection_object_t *c;
555 if (h -> type != omapi_type_connection)
556 return -1;
557 c = (omapi_connection_object_t *)h;
558 if (c -> state == omapi_connection_connecting)
559 return c -> socket;
560 if (c -> out_bytes)
561 return c -> socket;
562 else
563 return -1;
566 isc_result_t omapi_connection_connect (omapi_object_t *h)
568 isc_result_t status;
570 status = omapi_connection_connect_internal (h);
571 if (status != ISC_R_SUCCESS)
572 omapi_signal (h, "status", status);
573 return ISC_R_SUCCESS;
576 static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
578 int error;
579 omapi_connection_object_t *c;
580 SOCKLEN_T sl;
581 isc_result_t status;
583 if (h -> type != omapi_type_connection)
584 return ISC_R_INVALIDARG;
585 c = (omapi_connection_object_t *)h;
587 if (c -> state == omapi_connection_connecting) {
588 sl = sizeof error;
589 if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
590 (char *)&error, &sl) < 0) {
591 omapi_disconnect (h, 1);
592 return ISC_R_SUCCESS;
594 if (!error)
595 c -> state = omapi_connection_connected;
597 if (c -> state == omapi_connection_connecting ||
598 c -> state == omapi_connection_unconnected) {
599 if (c -> cptr >= c -> connect_list -> count) {
600 switch (error) {
601 case ECONNREFUSED:
602 status = ISC_R_CONNREFUSED;
603 break;
604 case ENETUNREACH:
605 status = ISC_R_NETUNREACH;
606 break;
607 default:
608 status = uerr2isc (error);
609 break;
611 omapi_disconnect (h, 1);
612 return status;
615 if (c -> connect_list -> addresses [c -> cptr].addrtype !=
616 AF_INET) {
617 omapi_disconnect (h, 1);
618 return ISC_R_INVALIDARG;
621 memcpy (&c -> remote_addr.sin_addr,
622 &c -> connect_list -> addresses [c -> cptr].address,
623 sizeof c -> remote_addr.sin_addr);
624 c -> remote_addr.sin_family = AF_INET;
625 c -> remote_addr.sin_port =
626 htons (c -> connect_list -> addresses [c -> cptr].port);
627 #if defined (HAVE_SA_LEN)
628 c -> remote_addr.sin_len = sizeof c -> remote_addr;
629 #endif
630 memset (&c -> remote_addr.sin_zero, 0,
631 sizeof c -> remote_addr.sin_zero);
632 ++c -> cptr;
634 error = connect (c -> socket,
635 (struct sockaddr *)&c -> remote_addr,
636 sizeof c -> remote_addr);
637 if (error < 0) {
638 error = errno;
639 if (error != EINPROGRESS) {
640 omapi_disconnect (h, 1);
641 switch (error) {
642 case ECONNREFUSED:
643 status = ISC_R_CONNREFUSED;
644 break;
645 case ENETUNREACH:
646 status = ISC_R_NETUNREACH;
647 break;
648 default:
649 status = uerr2isc (error);
650 break;
652 return status;
654 c -> state = omapi_connection_connecting;
655 return ISC_R_INCOMPLETE;
657 c -> state = omapi_connection_connected;
660 /* I don't know why this would fail, so I'm tempted not to test
661 the return value. */
662 sl = sizeof (c -> local_addr);
663 if (getsockname (c -> socket,
664 (struct sockaddr *)&c -> local_addr, &sl) < 0) {
667 /* Disconnect from I/O object, if any. */
668 if (h -> outer)
669 omapi_unregister_io_object (h);
671 status = omapi_register_io_object (h,
672 omapi_connection_readfd,
673 omapi_connection_writefd,
674 omapi_connection_reader,
675 omapi_connection_writer,
676 omapi_connection_reaper);
678 if (status != ISC_R_SUCCESS) {
679 omapi_disconnect (h, 1);
680 return status;
683 omapi_signal_in (h, "connect");
684 omapi_addr_list_dereference (&c -> connect_list, MDL);
685 return ISC_R_SUCCESS;
688 /* Reaper function for connection - if the connection is completely closed,
689 reap it. If it's in the disconnecting state, there were bytes left
690 to write when the user closed it, so if there are now no bytes left to
691 write, we can close it. */
692 isc_result_t omapi_connection_reaper (omapi_object_t *h)
694 omapi_connection_object_t *c;
696 if (h -> type != omapi_type_connection)
697 return ISC_R_INVALIDARG;
699 c = (omapi_connection_object_t *)h;
700 if (c -> state == omapi_connection_disconnecting &&
701 c -> out_bytes == 0) {
702 #ifdef DEBUG_PROTOCOL
703 log_debug ("omapi_connection_reaper(): disconnect");
704 #endif
705 omapi_disconnect (h, 1);
707 if (c -> state == omapi_connection_closed) {
708 #ifdef DEBUG_PROTOCOL
709 log_debug ("omapi_connection_reaper(): closed");
710 #endif
711 return ISC_R_NOTCONNECTED;
713 return ISC_R_SUCCESS;
716 static isc_result_t make_dst_key (DST_KEY **dst_key, omapi_object_t *a) {
717 omapi_value_t *name = (omapi_value_t *)0;
718 omapi_value_t *algorithm = (omapi_value_t *)0;
719 omapi_value_t *key = (omapi_value_t *)0;
720 int algorithm_id = UNKNOWN_KEYALG;
721 char *name_str = NULL;
722 isc_result_t status = ISC_R_SUCCESS;
724 if (status == ISC_R_SUCCESS)
725 status = omapi_get_value_str
726 (a, (omapi_object_t *)0, "name", &name);
728 if (status == ISC_R_SUCCESS)
729 status = omapi_get_value_str
730 (a, (omapi_object_t *)0, "algorithm", &algorithm);
732 if (status == ISC_R_SUCCESS)
733 status = omapi_get_value_str
734 (a, (omapi_object_t *)0, "key", &key);
736 if (status == ISC_R_SUCCESS) {
737 if ((algorithm -> value -> type == omapi_datatype_data ||
738 algorithm -> value -> type == omapi_datatype_string) &&
739 strncasecmp ((char *)algorithm -> value -> u.buffer.value,
740 NS_TSIG_ALG_HMAC_MD5 ".",
741 algorithm -> value -> u.buffer.len) == 0) {
742 algorithm_id = KEY_HMAC_MD5;
743 } else {
744 status = ISC_R_INVALIDARG;
748 if (status == ISC_R_SUCCESS) {
749 name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL);
750 if (!name_str)
751 status = ISC_R_NOMEMORY;
754 if (status == ISC_R_SUCCESS) {
755 memcpy (name_str,
756 name -> value -> u.buffer.value,
757 name -> value -> u.buffer.len);
758 name_str [name -> value -> u.buffer.len] = 0;
760 *dst_key = dst_buffer_to_key (name_str, algorithm_id, 0, 0,
761 key -> value -> u.buffer.value,
762 key -> value -> u.buffer.len);
763 if (!*dst_key)
764 status = ISC_R_NOMEMORY;
767 if (name_str)
768 dfree (name_str, MDL);
769 if (key)
770 omapi_value_dereference (&key, MDL);
771 if (algorithm)
772 omapi_value_dereference (&algorithm, MDL);
773 if (name)
774 omapi_value_dereference (&name, MDL);
776 return status;
779 isc_result_t omapi_connection_sign_data (int mode,
780 DST_KEY *key,
781 void **context,
782 const unsigned char *data,
783 const unsigned len,
784 omapi_typed_data_t **result)
786 omapi_typed_data_t *td = (omapi_typed_data_t *)0;
787 isc_result_t status;
788 int r;
790 if (mode & SIG_MODE_FINAL) {
791 status = omapi_typed_data_new (MDL, &td,
792 omapi_datatype_data,
793 dst_sig_size (key));
794 if (status != ISC_R_SUCCESS)
795 return status;
798 r = dst_sign_data (mode, key, context, data, len,
799 td ? td -> u.buffer.value : (u_char *)0,
800 td ? td -> u.buffer.len : 0);
802 /* dst_sign_data() really should do this for us, shouldn't it? */
803 if (mode & SIG_MODE_FINAL)
804 *context = (void *)0;
806 if (r < 0) {
807 if (td)
808 omapi_typed_data_dereference (&td, MDL);
809 return ISC_R_INVALIDKEY;
812 if (result && td) {
813 omapi_typed_data_reference (result, td, MDL);
816 if (td)
817 omapi_typed_data_dereference (&td, MDL);
819 return ISC_R_SUCCESS;
822 isc_result_t omapi_connection_output_auth_length (omapi_object_t *h,
823 unsigned *l)
825 omapi_connection_object_t *c;
827 if (h -> type != omapi_type_connection)
828 return ISC_R_INVALIDARG;
829 c = (omapi_connection_object_t *)h;
831 if (!c -> out_key)
832 return ISC_R_NOTFOUND;
834 *l = dst_sig_size (c -> out_key);
835 return ISC_R_SUCCESS;
838 isc_result_t omapi_connection_set_value (omapi_object_t *h,
839 omapi_object_t *id,
840 omapi_data_string_t *name,
841 omapi_typed_data_t *value)
843 omapi_connection_object_t *c;
844 isc_result_t status;
846 if (h -> type != omapi_type_connection)
847 return ISC_R_INVALIDARG;
848 c = (omapi_connection_object_t *)h;
850 if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
851 if (value && value -> type != omapi_datatype_object)
852 return ISC_R_INVALIDARG;
854 if (c -> in_context) {
855 omapi_connection_sign_data (SIG_MODE_FINAL,
856 c -> in_key,
857 &c -> in_context,
858 0, 0,
859 (omapi_typed_data_t **) 0);
862 if (c -> in_key) {
863 dst_free_key (c -> in_key);
864 c -> in_key = (DST_KEY *)0;
867 if (value) {
868 status = make_dst_key (&c -> in_key,
869 value -> u.object);
870 if (status != ISC_R_SUCCESS)
871 return status;
874 return ISC_R_SUCCESS;
876 else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
877 if (value && value -> type != omapi_datatype_object)
878 return ISC_R_INVALIDARG;
880 if (c -> out_context) {
881 omapi_connection_sign_data (SIG_MODE_FINAL,
882 c -> out_key,
883 &c -> out_context,
884 0, 0,
885 (omapi_typed_data_t **) 0);
888 if (c -> out_key) {
889 dst_free_key (c -> out_key);
890 c -> out_key = (DST_KEY *)0;
893 if (value) {
894 status = make_dst_key (&c -> out_key,
895 value -> u.object);
896 if (status != ISC_R_SUCCESS)
897 return status;
900 return ISC_R_SUCCESS;
903 if (h -> inner && h -> inner -> type -> set_value)
904 return (*(h -> inner -> type -> set_value))
905 (h -> inner, id, name, value);
906 return ISC_R_NOTFOUND;
909 isc_result_t omapi_connection_get_value (omapi_object_t *h,
910 omapi_object_t *id,
911 omapi_data_string_t *name,
912 omapi_value_t **value)
914 omapi_connection_object_t *c;
915 omapi_typed_data_t *td = (omapi_typed_data_t *)0;
916 isc_result_t status;
918 if (h -> type != omapi_type_connection)
919 return ISC_R_INVALIDARG;
920 c = (omapi_connection_object_t *)h;
922 if (omapi_ds_strcmp (name, "input-signature") == 0) {
923 if (!c -> in_key || !c -> in_context)
924 return ISC_R_NOTFOUND;
926 status = omapi_connection_sign_data (SIG_MODE_FINAL,
927 c -> in_key,
928 &c -> in_context,
929 0, 0, &td);
930 if (status != ISC_R_SUCCESS)
931 return status;
933 status = omapi_make_value (value, name, td, MDL);
934 omapi_typed_data_dereference (&td, MDL);
935 return status;
937 } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
938 if (!c -> in_key)
939 return ISC_R_NOTFOUND;
941 return omapi_make_int_value (value, name,
942 dst_sig_size (c -> in_key), MDL);
944 } else if (omapi_ds_strcmp (name, "output-signature") == 0) {
945 if (!c -> out_key || !c -> out_context)
946 return ISC_R_NOTFOUND;
948 status = omapi_connection_sign_data (SIG_MODE_FINAL,
949 c -> out_key,
950 &c -> out_context,
951 0, 0, &td);
952 if (status != ISC_R_SUCCESS)
953 return status;
955 status = omapi_make_value (value, name, td, MDL);
956 omapi_typed_data_dereference (&td, MDL);
957 return status;
959 } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
960 if (!c -> out_key)
961 return ISC_R_NOTFOUND;
963 return omapi_make_int_value (value, name,
964 dst_sig_size (c -> out_key), MDL);
967 if (h -> inner && h -> inner -> type -> get_value)
968 return (*(h -> inner -> type -> get_value))
969 (h -> inner, id, name, value);
970 return ISC_R_NOTFOUND;
973 isc_result_t omapi_connection_destroy (omapi_object_t *h,
974 const char *file, int line)
976 omapi_connection_object_t *c;
978 #ifdef DEBUG_PROTOCOL
979 log_debug ("omapi_connection_destroy()");
980 #endif
982 if (h -> type != omapi_type_connection)
983 return ISC_R_UNEXPECTED;
984 c = (omapi_connection_object_t *)(h);
985 if (c -> state == omapi_connection_connected)
986 omapi_disconnect (h, 1);
987 if (c -> listener)
988 omapi_listener_dereference (&c -> listener, file, line);
989 if (c -> connect_list)
990 omapi_addr_list_dereference (&c -> connect_list, file, line);
991 return ISC_R_SUCCESS;
994 isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
995 const char *name, va_list ap)
997 if (h -> type != omapi_type_connection)
998 return ISC_R_INVALIDARG;
1000 #ifdef DEBUG_PROTOCOL
1001 log_debug ("omapi_connection_signal_handler(%s)", name);
1002 #endif
1004 if (h -> inner && h -> inner -> type -> signal_handler)
1005 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
1006 name, ap);
1007 return ISC_R_NOTFOUND;
1010 /* Write all the published values associated with the object through the
1011 specified connection. */
1013 isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
1014 omapi_object_t *id,
1015 omapi_object_t *m)
1017 // int i;
1019 if (m -> type != omapi_type_connection)
1020 return ISC_R_INVALIDARG;
1022 if (m -> inner && m -> inner -> type -> stuff_values)
1023 return (*(m -> inner -> type -> stuff_values)) (c, id,
1024 m -> inner);
1025 return ISC_R_SUCCESS;