Annotation of embedaddon/dhcp/omapip/listener.c, revision 1.1
1.1 ! misho 1: /* listener.c
! 2:
! 3: Subroutines that support the generic listener object. */
! 4:
! 5: /*
! 6: * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
! 7: * Copyright (c) 1999-2003 by Internet Software Consortium
! 8: *
! 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.
! 12: *
! 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.
! 20: *
! 21: * Internet Systems Consortium, Inc.
! 22: * 950 Charter Street
! 23: * Redwood City, CA 94063
! 24: * <info@isc.org>
! 25: * https://www.isc.org/
! 26: *
! 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: * ``https://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''.
! 33: */
! 34:
! 35: #include "dhcpd.h"
! 36:
! 37: #include <omapip/omapip_p.h>
! 38: #include <errno.h>
! 39:
! 40: #if defined (TRACING)
! 41: omapi_array_t *trace_listeners;
! 42: static void trace_listener_accept_input (trace_type_t *, unsigned, char *);
! 43: static void trace_listener_remember (omapi_listener_object_t *,
! 44: const char *, int);
! 45: static void trace_listener_accept_stop (trace_type_t *);
! 46: trace_type_t *trace_listener_accept;
! 47: #endif
! 48:
! 49: OMAPI_OBJECT_ALLOC (omapi_listener,
! 50: omapi_listener_object_t, omapi_type_listener)
! 51:
! 52: isc_result_t omapi_listen (omapi_object_t *h,
! 53: unsigned port,
! 54: int max)
! 55: {
! 56: omapi_addr_t addr;
! 57:
! 58: #ifdef DEBUG_PROTOCOL
! 59: log_debug ("omapi_listen(port=%d, max=%d)", port, max);
! 60: #endif
! 61:
! 62: addr.addrtype = AF_INET;
! 63: addr.addrlen = sizeof (struct in_addr);
! 64: memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */
! 65: addr.port = port;
! 66:
! 67: return omapi_listen_addr (h, &addr, max);
! 68: }
! 69:
! 70: isc_result_t omapi_listen_addr (omapi_object_t *h,
! 71: omapi_addr_t *addr,
! 72: int max)
! 73: {
! 74: isc_result_t status;
! 75: omapi_listener_object_t *obj;
! 76: int i;
! 77:
! 78: /* Currently only support IPv4 addresses. */
! 79: if (addr->addrtype != AF_INET)
! 80: return ISC_R_INVALIDARG;
! 81:
! 82: /* Get the handle. */
! 83: obj = (omapi_listener_object_t *)0;
! 84: status = omapi_listener_allocate (&obj, MDL);
! 85: if (status != ISC_R_SUCCESS)
! 86: return status;
! 87: obj->socket = -1;
! 88:
! 89: /* Connect this object to the inner object. */
! 90: status = omapi_object_reference (&h -> outer,
! 91: (omapi_object_t *)obj, MDL);
! 92: if (status != ISC_R_SUCCESS)
! 93: goto error_exit;
! 94: status = omapi_object_reference (&obj -> inner, h, MDL);
! 95: if (status != ISC_R_SUCCESS)
! 96: goto error_exit;
! 97:
! 98: /* Set up the address on which we will listen... */
! 99: obj -> address.sin_port = htons (addr -> port);
! 100: memcpy (&obj -> address.sin_addr,
! 101: addr -> address, sizeof obj -> address.sin_addr);
! 102: #if defined (HAVE_SA_LEN)
! 103: obj -> address.sin_len =
! 104: sizeof (struct sockaddr_in);
! 105: #endif
! 106: obj -> address.sin_family = AF_INET;
! 107: memset (&(obj -> address.sin_zero), 0,
! 108: sizeof obj -> address.sin_zero);
! 109:
! 110: #if defined (TRACING)
! 111: /* If we're playing back a trace file, we remember the object
! 112: on the trace listener queue. */
! 113: if (trace_playback ()) {
! 114: trace_listener_remember (obj, MDL);
! 115: } else {
! 116: #endif
! 117: /* Create a socket on which to listen. */
! 118: obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
! 119: if (obj->socket == -1) {
! 120: if (errno == EMFILE
! 121: || errno == ENFILE || errno == ENOBUFS)
! 122: status = ISC_R_NORESOURCES;
! 123: else
! 124: status = ISC_R_UNEXPECTED;
! 125: goto error_exit;
! 126: }
! 127:
! 128: #if defined (HAVE_SETFD)
! 129: if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
! 130: status = ISC_R_UNEXPECTED;
! 131: goto error_exit;
! 132: }
! 133: #endif
! 134:
! 135: /* Set the REUSEADDR option so that we don't fail to start if
! 136: we're being restarted. */
! 137: i = 1;
! 138: if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
! 139: (char *)&i, sizeof i) < 0) {
! 140: status = ISC_R_UNEXPECTED;
! 141: goto error_exit;
! 142: }
! 143:
! 144: /* Try to bind to the wildcard address using the port number
! 145: we were given. */
! 146: i = bind (obj -> socket,
! 147: (struct sockaddr *)&obj -> address,
! 148: sizeof obj -> address);
! 149: if (i < 0) {
! 150: if (errno == EADDRINUSE)
! 151: status = ISC_R_ADDRNOTAVAIL;
! 152: else if (errno == EPERM)
! 153: status = ISC_R_NOPERM;
! 154: else
! 155: status = ISC_R_UNEXPECTED;
! 156: goto error_exit;
! 157: }
! 158:
! 159: /* Now tell the kernel to listen for connections. */
! 160: if (listen (obj -> socket, max)) {
! 161: status = ISC_R_UNEXPECTED;
! 162: goto error_exit;
! 163: }
! 164:
! 165: if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
! 166: status = ISC_R_UNEXPECTED;
! 167: goto error_exit;
! 168: }
! 169:
! 170: status = omapi_register_io_object ((omapi_object_t *)obj,
! 171: omapi_listener_readfd, 0,
! 172: omapi_accept, 0, 0);
! 173: #if defined (TRACING)
! 174: }
! 175: #endif
! 176:
! 177: omapi_listener_dereference (&obj, MDL);
! 178: return status;
! 179:
! 180: error_exit:
! 181: if (obj != NULL) {
! 182: if (h->outer == (omapi_object_t *)obj) {
! 183: omapi_object_dereference((omapi_object_t **)&h->outer,
! 184: MDL);
! 185: }
! 186: if (obj->inner == h) {
! 187: omapi_object_dereference((omapi_object_t **)&obj->inner,
! 188: MDL);
! 189: }
! 190: if (obj->socket != -1) {
! 191: close(obj->socket);
! 192: }
! 193: omapi_listener_dereference(&obj, MDL);
! 194: }
! 195: return status;
! 196: }
! 197:
! 198: /* Return the socket on which the dispatcher should wait for readiness
! 199: to read, for a listener object. */
! 200: int omapi_listener_readfd (omapi_object_t *h)
! 201: {
! 202: omapi_listener_object_t *l;
! 203:
! 204: if (h -> type != omapi_type_listener)
! 205: return -1;
! 206: l = (omapi_listener_object_t *)h;
! 207:
! 208: return l -> socket;
! 209: }
! 210:
! 211: /* Reader callback for a listener object. Accept an incoming connection. */
! 212: isc_result_t omapi_accept (omapi_object_t *h)
! 213: {
! 214: isc_result_t status;
! 215: socklen_t len;
! 216: omapi_connection_object_t *obj;
! 217: omapi_listener_object_t *listener;
! 218: struct sockaddr_in addr;
! 219: int socket;
! 220:
! 221: if (h -> type != omapi_type_listener)
! 222: return ISC_R_INVALIDARG;
! 223: listener = (omapi_listener_object_t *)h;
! 224:
! 225: /* Accept the connection. */
! 226: len = sizeof addr;
! 227: socket = accept (listener -> socket,
! 228: ((struct sockaddr *)&(addr)), &len);
! 229: if (socket < 0) {
! 230: if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS)
! 231: return ISC_R_NORESOURCES;
! 232: return ISC_R_UNEXPECTED;
! 233: }
! 234:
! 235: #if defined (TRACING)
! 236: /* If we're recording a trace, remember the connection. */
! 237: if (trace_record ()) {
! 238: trace_iov_t iov [3];
! 239: iov [0].buf = (char *)&addr.sin_port;
! 240: iov [0].len = sizeof addr.sin_port;
! 241: iov [1].buf = (char *)&addr.sin_addr;
! 242: iov [1].len = sizeof addr.sin_addr;
! 243: iov [2].buf = (char *)&listener -> address.sin_port;
! 244: iov [2].len = sizeof listener -> address.sin_port;
! 245: trace_write_packet_iov (trace_listener_accept,
! 246: 3, iov, MDL);
! 247: }
! 248: #endif
! 249:
! 250: obj = (omapi_connection_object_t *)0;
! 251: status = omapi_listener_connect (&obj, listener, socket, &addr);
! 252: if (status != ISC_R_SUCCESS) {
! 253: close (socket);
! 254: return status;
! 255: }
! 256:
! 257: status = omapi_register_io_object ((omapi_object_t *)obj,
! 258: omapi_connection_readfd,
! 259: omapi_connection_writefd,
! 260: omapi_connection_reader,
! 261: omapi_connection_writer,
! 262: omapi_connection_reaper);
! 263:
! 264: /* Lose our reference to the connection, so it'll be gc'd when it's
! 265: reaped. */
! 266: omapi_connection_dereference (&obj, MDL);
! 267: if (status != ISC_R_SUCCESS)
! 268: omapi_disconnect ((omapi_object_t *)(obj), 1);
! 269: return status;
! 270: }
! 271:
! 272: isc_result_t omapi_listener_connect (omapi_connection_object_t **obj,
! 273: omapi_listener_object_t *listener,
! 274: int socket,
! 275: struct sockaddr_in *remote_addr)
! 276: {
! 277: isc_result_t status;
! 278: omapi_object_t *h = (omapi_object_t *)listener;
! 279: omapi_addr_t addr;
! 280:
! 281: #ifdef DEBUG_PROTOCOL
! 282: log_debug ("omapi_accept()");
! 283: #endif
! 284:
! 285: /* Get the handle. */
! 286: status = omapi_connection_allocate (obj, MDL);
! 287: if (status != ISC_R_SUCCESS)
! 288: return status;
! 289:
! 290: (*obj) -> state = omapi_connection_connected;
! 291: (*obj) -> remote_addr = *remote_addr;
! 292: (*obj) -> socket = socket;
! 293:
! 294: /* Verify that this host is allowed to connect. */
! 295: if (listener -> verify_addr) {
! 296: addr.addrtype = AF_INET;
! 297: addr.addrlen = sizeof (remote_addr -> sin_addr);
! 298: memcpy (addr.address, &remote_addr -> sin_addr,
! 299: sizeof (remote_addr -> sin_addr));
! 300: addr.port = ntohs(remote_addr -> sin_port);
! 301:
! 302: status = (listener -> verify_addr) (h, &addr);
! 303: if (status != ISC_R_SUCCESS) {
! 304: omapi_disconnect ((omapi_object_t *)(*obj), 1);
! 305: omapi_connection_dereference (obj, MDL);
! 306: return status;
! 307: }
! 308: }
! 309:
! 310: omapi_listener_reference (&(*obj) -> listener, listener, MDL);
! 311: #if defined (TRACING)
! 312: omapi_connection_register (*obj, MDL);
! 313: #endif
! 314: status = omapi_signal (h, "connect", (*obj));
! 315: return status;
! 316: }
! 317:
! 318: #if defined (TRACING)
! 319: OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t)
! 320:
! 321: void omapi_listener_trace_setup (void) {
! 322: trace_listener_accept =
! 323: trace_type_register ("listener-accept", (void *)0,
! 324: trace_listener_accept_input,
! 325: trace_listener_accept_stop, MDL);
! 326: }
! 327:
! 328: static void trace_listener_remember (omapi_listener_object_t *obj,
! 329: const char *file, int line)
! 330: {
! 331: isc_result_t status;
! 332: if (!trace_listeners) {
! 333: status = omapi_listener_array_allocate (&trace_listeners,
! 334: file, line);
! 335: if (status != ISC_R_SUCCESS) {
! 336: foo:
! 337: log_error ("trace_listener_remember: %s",
! 338: isc_result_totext (status));
! 339: return;
! 340: }
! 341: }
! 342: status = omapi_listener_array_extend (trace_listeners, obj,
! 343: &obj -> index, MDL);
! 344: if (status != ISC_R_SUCCESS)
! 345: goto foo;
! 346: }
! 347:
! 348: static void trace_listener_accept_input (trace_type_t *ttype,
! 349: unsigned length, char *buf)
! 350: {
! 351: struct in_addr *addr;
! 352: u_int16_t *remote_port;
! 353: u_int16_t *local_port;
! 354: omapi_connection_object_t *obj;
! 355: isc_result_t status;
! 356: struct sockaddr_in remote_addr;
! 357:
! 358: addr = (struct in_addr *)buf;
! 359: remote_port = (u_int16_t *)(addr + 1);
! 360: local_port = remote_port + 1;
! 361:
! 362: memset (&remote_addr, 0, sizeof remote_addr);
! 363: remote_addr.sin_addr = *addr;
! 364: remote_addr.sin_port = *remote_port;
! 365:
! 366: omapi_array_foreach_begin (trace_listeners,
! 367: omapi_listener_object_t, lp) {
! 368: if (lp -> address.sin_port == *local_port) {
! 369: obj = (omapi_connection_object_t *)0;
! 370: status = omapi_listener_connect (&obj,
! 371: lp, 0, &remote_addr);
! 372: omapi_listener_dereference (&lp, MDL);
! 373: return;
! 374: }
! 375: } omapi_array_foreach_end (trace_listeners,
! 376: omapi_listener_object_t, lp);
! 377: log_error ("trace_listener_accept: %s from %s/%d to port %d",
! 378: "unexpected connect",
! 379: inet_ntoa (*addr), *remote_port, *local_port);
! 380: }
! 381:
! 382: static void trace_listener_accept_stop (trace_type_t *ttype) { }
! 383:
! 384:
! 385: #endif
! 386:
! 387: isc_result_t omapi_listener_configure_security (omapi_object_t *h,
! 388: isc_result_t (*verify_addr)
! 389: (omapi_object_t *,
! 390: omapi_addr_t *))
! 391: {
! 392: omapi_listener_object_t *l;
! 393:
! 394: if (h -> type != omapi_type_listener)
! 395: return ISC_R_INVALIDARG;
! 396: l = (omapi_listener_object_t *)h;
! 397:
! 398: l -> verify_addr = verify_addr;
! 399:
! 400: return ISC_R_SUCCESS;
! 401: }
! 402:
! 403: isc_result_t omapi_listener_set_value (omapi_object_t *h,
! 404: omapi_object_t *id,
! 405: omapi_data_string_t *name,
! 406: omapi_typed_data_t *value)
! 407: {
! 408: if (h -> type != omapi_type_listener)
! 409: return ISC_R_INVALIDARG;
! 410:
! 411: if (h -> inner && h -> inner -> type -> set_value)
! 412: return (*(h -> inner -> type -> set_value))
! 413: (h -> inner, id, name, value);
! 414: return ISC_R_NOTFOUND;
! 415: }
! 416:
! 417: isc_result_t omapi_listener_get_value (omapi_object_t *h,
! 418: omapi_object_t *id,
! 419: omapi_data_string_t *name,
! 420: omapi_value_t **value)
! 421: {
! 422: if (h -> type != omapi_type_listener)
! 423: return ISC_R_INVALIDARG;
! 424:
! 425: if (h -> inner && h -> inner -> type -> get_value)
! 426: return (*(h -> inner -> type -> get_value))
! 427: (h -> inner, id, name, value);
! 428: return ISC_R_NOTFOUND;
! 429: }
! 430:
! 431: isc_result_t omapi_listener_destroy (omapi_object_t *h,
! 432: const char *file, int line)
! 433: {
! 434: omapi_listener_object_t *l;
! 435:
! 436: if (h -> type != omapi_type_listener)
! 437: return ISC_R_INVALIDARG;
! 438: l = (omapi_listener_object_t *)h;
! 439:
! 440: #ifdef DEBUG_PROTOCOL
! 441: log_debug ("omapi_listener_destroy()");
! 442: #endif
! 443:
! 444: if (l -> socket != -1) {
! 445: close (l -> socket);
! 446: l -> socket = -1;
! 447: }
! 448: return ISC_R_SUCCESS;
! 449: }
! 450:
! 451: isc_result_t omapi_listener_signal_handler (omapi_object_t *h,
! 452: const char *name, va_list ap)
! 453: {
! 454: if (h -> type != omapi_type_listener)
! 455: return ISC_R_INVALIDARG;
! 456:
! 457: if (h -> inner && h -> inner -> type -> signal_handler)
! 458: return (*(h -> inner -> type -> signal_handler)) (h -> inner,
! 459: name, ap);
! 460: return ISC_R_NOTFOUND;
! 461: }
! 462:
! 463: /* Write all the published values associated with the object through the
! 464: specified connection. */
! 465:
! 466: isc_result_t omapi_listener_stuff_values (omapi_object_t *c,
! 467: omapi_object_t *id,
! 468: omapi_object_t *l)
! 469: {
! 470: if (l -> type != omapi_type_listener)
! 471: return ISC_R_INVALIDARG;
! 472:
! 473: if (l -> inner && l -> inner -> type -> stuff_values)
! 474: return (*(l -> inner -> type -> stuff_values)) (c, id,
! 475: l -> inner);
! 476: return ISC_R_SUCCESS;
! 477: }
! 478:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>