[BACK]Return to connection.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / mpl / dhcp / dist / omapip

Annotation of src/external/mpl/dhcp/dist/omapip/connection.c, Revision 1.3

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

CVSweb <webmaster@jp.NetBSD.org>