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>