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>