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