Annotation of embedaddon/dhcp/omapip/connection.c, revision 1.1.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>