Annotation of embedaddon/dhcp/omapip/listener.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>