Annotation of embedaddon/bmon/src/in_distribution.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * in_distribution.c     Distribution Input
        !             3:  *
        !             4:  * Copyright (c) 2001-2004 Thomas Graf <tgraf@suug.ch>
        !             5:  *
        !             6:  * Permission is hereby granted, free of charge, to any person obtaining a
        !             7:  * copy of this software and associated documentation files (the "Software"),
        !             8:  * to deal in the Software without restriction, including without limitation
        !             9:  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
        !            10:  * and/or sell copies of the Software, and to permit persons to whom the
        !            11:  * Software is furnished to do so, subject to the following conditions:
        !            12:  *
        !            13:  * The above copyright notice and this permission notice shall be included
        !            14:  * in all copies or substantial portions of the Software.
        !            15:  *
        !            16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
        !            17:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
        !            19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
        !            21:  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
        !            22:  * DEALINGS IN THE SOFTWARE.
        !            23:  */
        !            24: 
        !            25: #include <sys/ioctl.h>
        !            26: #include <fcntl.h>
        !            27: #include <netinet/in.h>
        !            28: #include <netdb.h>
        !            29: #include <inttypes.h>
        !            30: #include <sys/socket.h>
        !            31: #include <net/if.h>
        !            32: 
        !            33: #include <bmon/bmon.h>
        !            34: #include <bmon/input.h>
        !            35: #include <bmon/node.h>
        !            36: #include <bmon/item.h>
        !            37: #include <bmon/distribution.h>
        !            38: #include <bmon/utils.h>
        !            39: 
        !            40: #ifdef HAVE_SYS_SOCKIO_H
        !            41: #include <sys/sockio.h>
        !            42: #endif
        !            43: 
        !            44: static int recv_fd = -1;
        !            45: static char *c_port = "2048";
        !            46: static int c_port_int = 2048;
        !            47: static char *c_ip = NULL;
        !            48: static int c_ipv6 = 0;
        !            49: static int c_max_read = 10;
        !            50: static int c_bufsize = 8192;
        !            51: static int c_debug = 0;
        !            52: static int c_multicast = 0;
        !            53: static int c_bind = 1;
        !            54: static char *c_iface = NULL;
        !            55: static char *buf;
        !            56: 
        !            57: static int join_multicast4(int fd, struct sockaddr_in *addr, const char *iface)
        !            58: {
        !            59:        struct ip_mreq mreq;
        !            60:        struct ifreq ifreq;
        !            61:        unsigned char loop = 0;
        !            62: 
        !            63:        memcpy(&mreq.imr_multiaddr, &addr->sin_addr, sizeof(struct sockaddr_in));
        !            64:        strncpy(ifreq.ifr_name, iface, IFNAMSIZ);
        !            65: 
        !            66:        if (iface) {
        !            67:                if (ioctl(fd, SIOCGIFADDR, &ifreq) < 0)
        !            68:                        return -1;
        !            69: 
        !            70:                memcpy(&mreq.imr_interface,
        !            71:                        &((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr,
        !            72:                        sizeof(struct sockaddr_in));
        !            73:        } else
        !            74:                mreq.imr_interface.s_addr = htonl(INADDR_ANY);
        !            75:        
        !            76:        if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
        !            77:                return -1;
        !            78: 
        !            79:        return setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
        !            80: }
        !            81: 
        !            82: static int join_multicast6(int fd, struct sockaddr_in6 *addr, const char *iface)
        !            83: {
        !            84:        struct ipv6_mreq mreq6;
        !            85:        unsigned char loop = 0;
        !            86: 
        !            87:        memcpy(&mreq6.ipv6mr_multiaddr, &addr->sin6_addr, sizeof(struct sockaddr_in6));
        !            88: 
        !            89:        if (iface) {
        !            90:                return -1; /* XXX: unsupported atm */
        !            91:        } else
        !            92:                mreq6.ipv6mr_interface = 0;
        !            93: 
        !            94:        if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) < 0)
        !            95:                return -1;
        !            96: 
        !            97:        return setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop));
        !            98: }
        !            99: 
        !           100: static int join_multicast(int fd, struct sockaddr *sa, const char *iface)
        !           101: {
        !           102:        switch (sa->sa_family) {
        !           103:                case AF_INET:
        !           104:                        return join_multicast4(fd, (struct sockaddr_in *) sa, iface);
        !           105: 
        !           106:                case AF_INET6:
        !           107:                        return join_multicast6(fd, (struct sockaddr_in6 *) sa, iface);
        !           108:        }
        !           109: 
        !           110:        return -1;
        !           111: }
        !           112: 
        !           113: static int distribution_probe(void)
        !           114: {
        !           115:        if (c_ip) {
        !           116:                int err;
        !           117:                char s[INET6_ADDRSTRLEN];
        !           118:                struct addrinfo hints = {
        !           119:                        .ai_socktype = SOCK_DGRAM,
        !           120:                        .ai_family = c_ipv6 ? PF_INET6 : PF_INET,
        !           121:                };
        !           122:                struct addrinfo *res = NULL, *t;
        !           123: 
        !           124:                if (c_ipv6 && !strcmp(c_ip, "224.0.0.1"))
        !           125:                        c_ip = "ff01::1";
        !           126: 
        !           127:                if ((err = getaddrinfo(c_ip, c_port, &hints, &res)) < 0)
        !           128:                        quit("getaddrinfo failed: %s\n", gai_strerror(err));
        !           129: 
        !           130:                for (t = res; t; t = t->ai_next) {
        !           131:                        if (c_debug) {
        !           132:                                const char *x = xinet_ntop(t->ai_addr, s, sizeof(s));
        !           133:                                fprintf(stderr, "Trying %s...", x ? x : "null");
        !           134:                        }
        !           135:                        recv_fd = socket(t->ai_family, t->ai_socktype, 0);
        !           136: 
        !           137:                        if (recv_fd < 0) {
        !           138:                                if (c_debug)
        !           139:                                        fprintf(stderr, "socket() failed: %s\n", strerror(errno));
        !           140:                                continue;
        !           141:                        }
        !           142: 
        !           143:                        if (c_multicast) {
        !           144:                                if (join_multicast(recv_fd, t->ai_addr, c_iface) < 0)
        !           145:                                        continue;
        !           146: 
        !           147:                                if (!c_bind)
        !           148:                                        goto skip_bind;
        !           149:                        }
        !           150: 
        !           151:                        if (bind(recv_fd, t->ai_addr, t->ai_addrlen) < 0) {
        !           152:                                if (c_debug)
        !           153:                                        fprintf(stderr, "bind() failed: %s\n", strerror(errno));
        !           154:                                continue;
        !           155:                        }
        !           156: skip_bind:
        !           157: 
        !           158:                        if (c_debug)
        !           159:                                fprintf(stderr, "OK\n");
        !           160: 
        !           161:                        goto ok;
        !           162:                }
        !           163: 
        !           164:                fprintf(stderr, "Could not create and connect a datagram " \
        !           165:                        "socket, tried:\n");
        !           166: 
        !           167:                for (t = res; t; t = t->ai_next) {
        !           168:                        const char *x = xinet_ntop(t->ai_addr, s, sizeof(s));
        !           169:                        fprintf(stderr, "\t%s\n", x ? x : "null");
        !           170:                }
        !           171: 
        !           172:                quit("Last error message was: %s\n", strerror(errno));
        !           173:        } else {
        !           174:                if (c_ipv6) {
        !           175:                        struct sockaddr_in6 addr = {
        !           176:                                .sin6_family = AF_INET6,
        !           177:                                .sin6_addr = IN6ADDR_ANY_INIT,
        !           178:                                .sin6_port = htons(c_port_int),
        !           179:                        };
        !           180: 
        !           181:                        recv_fd = socket(AF_INET6, SOCK_DGRAM, 0);
        !           182: 
        !           183:                        if (recv_fd < 0)
        !           184:                                goto try_4;
        !           185: 
        !           186:                        if (bind(recv_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
        !           187:                                goto try_4;
        !           188: 
        !           189:                        goto ok;
        !           190:                }
        !           191: try_4:
        !           192:                recv_fd = socket(AF_INET, SOCK_DGRAM, 0);
        !           193: 
        !           194:                if (recv_fd < 0)
        !           195:                        quit("socket creation failed: %s\n", strerror(errno));
        !           196:                {
        !           197:                        struct sockaddr_in addr = {
        !           198:                                .sin_family = AF_INET,
        !           199:                                .sin_port = htons(c_port_int),
        !           200:                        };
        !           201: 
        !           202:                        /* Guess what, NetBSD is fucked up so this can't
        !           203:                         * be in the initializer */
        !           204:                        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        !           205: 
        !           206:                        if (bind(recv_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
        !           207:                                quit("bind failed: %s\n", strerror(errno));
        !           208:                }
        !           209: 
        !           210:                goto ok;
        !           211:        }
        !           212: 
        !           213: ok:
        !           214:        {
        !           215:                int flags;
        !           216:                
        !           217:                if ((flags = fcntl(recv_fd, F_GETFL)) < 0)
        !           218:                        quit("fcntl failed: %s\n", strerror(errno));
        !           219:                
        !           220:                if (fcntl(recv_fd, F_SETFL, flags | O_NONBLOCK) < 0)
        !           221:                        quit("fcntl failed: %s\n", strerror(errno));
        !           222: 
        !           223:        }
        !           224: 
        !           225:        return 1;
        !           226: }
        !           227: 
        !           228: static int process_item(struct distr_msg_hdr *hdr, const char *nodename,
        !           229:                        struct distr_msg_item *intf, char *from)
        !           230: {
        !           231:        char *intfname;
        !           232:        int remaining, offset;
        !           233:        char *desc = NULL;
        !           234:        uint32_t handle = 0;
        !           235:        int rx_usage = -1, tx_usage = -1;
        !           236:        int parent = 0, level = 0, link = 0, index = 0;
        !           237: 
        !           238:        item_t *local_intf, *parent_intf;
        !           239:        node_t *remote_node;
        !           240: 
        !           241:        intfname = ((char *) intf) + sizeof(*intf);
        !           242: 
        !           243:        if (c_debug)
        !           244:                fprintf(stderr, "Processing interface %s (offset: %d " \
        !           245:                        "optslen: %d namelen: %d hdrsize: %lu)\n",
        !           246:                        intfname ? intfname : "null", ntohs(intf->i_offset),
        !           247:                        intf->i_optslen, intf->i_namelen, (unsigned long) sizeof(*intf));
        !           248: 
        !           249:        if (intf->i_namelen < 4 || intf->i_namelen > IFNAME_MAX) {
        !           250:                if (c_debug)
        !           251:                        fprintf(stderr, "Discarding malformed packet (invalid namelen %d)\n",
        !           252:                                intf->i_namelen);
        !           253:                return -1;
        !           254:        }
        !           255: 
        !           256:        if ('\0' == *intfname) {
        !           257:                if (c_debug)
        !           258:                        fprintf(stderr, "Discarding malformed packet (empty linkname)\n");
        !           259:                return -1;
        !           260:        }
        !           261: 
        !           262:        index = ntohs(intf->i_index);
        !           263: 
        !           264:        if (intf->i_optslen) {
        !           265:                offset = sizeof(*intf) + intf->i_namelen;
        !           266:                remaining = intf->i_optslen;
        !           267: 
        !           268:                while (remaining > 0) {
        !           269:                        struct distr_msg_ifopt *opt;
        !           270: 
        !           271:                        opt = (struct distr_msg_ifopt *) (((char *) intf) + offset);
        !           272: 
        !           273:                        if (opt->io_len > (remaining - sizeof(*opt))) {
        !           274:                                if (c_debug)
        !           275:                                        fprintf(stderr, "Discarding malformed packet (invalid opt len)\n");
        !           276:                                return -1;
        !           277:                        }
        !           278: 
        !           279:                        switch (opt->io_type) {
        !           280:                                case IFOPT_HANDLE:
        !           281:                                        if (opt->io_len != sizeof(uint32_t)) {
        !           282:                                                if (c_debug)
        !           283:                                                        fprintf(stderr, "Discarding malformed packet " \
        !           284:                                                                "(invalid opt len for handle)\n");
        !           285:                                                return -1;
        !           286:                                        }
        !           287: 
        !           288:                                        handle = ntohl(*(uint32_t *) (((char *) opt) + sizeof (*opt)));
        !           289:                                        break;
        !           290: 
        !           291:                                case IFOPT_PARENT:
        !           292:                                        parent = ntohs(opt->io_pad);
        !           293:                                        break;
        !           294: 
        !           295:                                case IFOPT_LEVEL:
        !           296:                                        level = ntohs(opt->io_pad);
        !           297:                                        break;
        !           298: 
        !           299:                                case IFOPT_LINK:
        !           300:                                        link = ntohs(opt->io_pad);
        !           301:                                        break;
        !           302: 
        !           303:                                case IFOPT_RX_USAGE:
        !           304:                                        if (opt->io_len != sizeof(uint32_t)) {
        !           305:                                                if (c_debug)
        !           306:                                                        fprintf(stderr, "Discarding malformed packet " \
        !           307:                                                                "(invalid opt len for rx usage)\n");
        !           308:                                                return -1;
        !           309:                                        }
        !           310: 
        !           311:                                        rx_usage = ntohl(*(uint32_t *) (((char *)opt) + sizeof (*opt)));
        !           312:                                        break;
        !           313: 
        !           314:                                case IFOPT_TX_USAGE:
        !           315:                                        if (opt->io_len != sizeof(uint32_t)) {
        !           316:                                                if (c_debug)
        !           317:                                                        fprintf(stderr, "Discarding malformed packet " \
        !           318:                                                                "(invalid opt len for tx usage)\n");
        !           319:                                                return -1;
        !           320:                                        }
        !           321: 
        !           322:                                        tx_usage = ntohl(*(uint32_t *) (((char *)opt) + sizeof (*opt)));
        !           323:                                        break;
        !           324: 
        !           325:                                case IFOPT_DESC:
        !           326:                                        if (opt->io_len <= 0) {
        !           327:                                                if (c_debug)
        !           328:                                                        fprintf(stderr, "Discarding malformed packet " \
        !           329:                                                                "(invalid opt len for description)\n");
        !           330:                                                return -1;
        !           331:                                        }
        !           332: 
        !           333:                                        desc = ((char *) opt) + sizeof(*opt);
        !           334:                                        break;
        !           335:                        }
        !           336: 
        !           337:                        remaining -= (sizeof(*opt) + opt->io_len);
        !           338:                        offset += (sizeof(*opt) + opt->io_len);
        !           339:                }
        !           340:        
        !           341:                if (remaining < 0)
        !           342:                        if (c_debug)
        !           343:                                fprintf(stderr, "Leftover from options: %d\n", abs(remaining));
        !           344:        }
        !           345: 
        !           346:        remote_node = lookup_node(nodename, 1);
        !           347: 
        !           348:        if (NULL == remote_node) {
        !           349:                if (c_debug)
        !           350:                        fprintf(stderr, "Could not create node entry for remote node\n");
        !           351:                return -1;
        !           352:        }
        !           353: 
        !           354:        if (remote_node->n_from)
        !           355:                xfree((void *) remote_node->n_from);
        !           356:        remote_node->n_from = strdup(from);
        !           357: 
        !           358:        if (ntohs(intf->i_flags) & IF_IS_CHILD) {
        !           359:                parent_intf = get_item(remote_node, parent);
        !           360:                if (parent_intf == NULL) {
        !           361:                        if (c_debug)
        !           362:                                fprintf(stderr, "Could not find parent interface for remote interface\n");
        !           363:                        return -1;
        !           364:                }
        !           365:        } else
        !           366:                parent_intf = NULL;
        !           367: 
        !           368:        local_intf = lookup_item(remote_node, intfname, handle, parent_intf);
        !           369:        if (local_intf == NULL) {
        !           370:                if (c_debug)
        !           371:                        fprintf(stderr, "Could not crate interface for remote interface\n");
        !           372:                return -1;
        !           373:        }
        !           374: 
        !           375:        if (local_intf->i_flags & ITEM_FLAG_LOCAL) {
        !           376:                if (c_debug)
        !           377:                        fprintf(stderr, "Discarding malformed packet " \
        !           378:                                        "(about to overwrite a local item)\n");
        !           379:                return -1;
        !           380:        }
        !           381: 
        !           382:        local_intf->i_major_attr = BYTES;
        !           383:        local_intf->i_minor_attr = PACKETS;
        !           384: 
        !           385:        local_intf->i_rx_usage = rx_usage;
        !           386:        local_intf->i_tx_usage = tx_usage;
        !           387: 
        !           388:        if (desc) {
        !           389:                if (local_intf->i_desc && strcmp(local_intf->i_desc, desc)) {
        !           390:                        free(local_intf->i_desc);
        !           391:                        local_intf->i_desc = NULL;
        !           392:                }
        !           393: 
        !           394:                if (local_intf->i_desc == NULL)
        !           395:                        local_intf->i_desc = strdup(desc);
        !           396:        }
        !           397:                
        !           398:        offset = sizeof(*intf) + intf->i_optslen + intf->i_namelen;
        !           399:        remaining = ntohs(intf->i_offset) - offset;
        !           400: 
        !           401:        while (remaining > 0) {
        !           402:                struct distr_msg_attr *attr;
        !           403:                uint64_t rx, tx;
        !           404:                int type;
        !           405:                attr = (struct distr_msg_attr *) (((char *) intf) + offset);
        !           406: 
        !           407:                type = ntohs(attr->a_type);
        !           408:                rx = xntohll(attr->a_rx);
        !           409:                tx = xntohll(attr->a_tx);
        !           410: 
        !           411:                if (c_debug)
        !           412:                        fprintf(stderr, "Attribute type %d %" PRIu64 " %" PRIu64 "\n",
        !           413:                                type, rx, tx);
        !           414: 
        !           415:                if (type >= ATTR_MAX)
        !           416:                        goto skip;
        !           417: 
        !           418:                if (1) {
        !           419:                        int aflags = ntohs(attr->a_flags);
        !           420:                        int flags = (aflags & ATTR_RX_PROVIDED ? RX_PROVIDED : 0) |
        !           421:                                    (aflags & ATTR_TX_PROVIDED ? TX_PROVIDED : 0);
        !           422: 
        !           423:                        update_attr(local_intf, type, rx, tx, flags);
        !           424:                }
        !           425: 
        !           426: skip:
        !           427:                remaining -= sizeof(*attr);
        !           428:                offset += sizeof(*attr);
        !           429:        }
        !           430: 
        !           431:        if (ntohs(intf->i_flags) & IF_IS_CHILD)
        !           432:                local_intf->i_flags |= ITEM_FLAG_IS_CHILD;
        !           433:        local_intf->i_level = level;
        !           434:        local_intf->i_link = link;
        !           435: 
        !           436:        if (1) {
        !           437:                timestamp_t ts = {
        !           438:                        .tv_sec = ntohl(hdr->h_ts_sec),
        !           439:                        .tv_usec = ntohl(hdr->h_ts_usec)
        !           440:                };
        !           441: 
        !           442:                notify_update(local_intf, &ts);
        !           443:        }
        !           444: 
        !           445:        increase_lifetime(local_intf, 1);
        !           446: 
        !           447:        if (remaining < 0)
        !           448:                if (c_debug)
        !           449:                        fprintf(stderr, "Leftover from attributes: %d\n", abs(remaining));
        !           450: 
        !           451:        return 0;
        !           452: }
        !           453: 
        !           454: static void process_group(struct distr_msg_hdr *hdr, const char *nodename,
        !           455:                          struct distr_msg_grp *grp, char *from)
        !           456: {
        !           457:        int remaining, offset;
        !           458:        int grpoffset;
        !           459:        
        !           460:        if (c_debug)
        !           461:                fprintf(stderr, "Processing group (type:%d offset:%d)\n",
        !           462:                        ntohs(grp->g_type), ntohs(grp->g_offset));
        !           463: 
        !           464:        if (ntohs(grp->g_type) != BMON_GRP_IF) {
        !           465:                if (c_debug)
        !           466:                        fprintf(stderr, "Discarding malformed packet (invalid group type)\n");
        !           467:                return;
        !           468:        }
        !           469: 
        !           470:        grpoffset = ntohs(grp->g_offset);
        !           471: 
        !           472:        if (grpoffset < sizeof(*grp) || grpoffset > ntohs(hdr->h_len)) {
        !           473:                if (c_debug)
        !           474:                        fprintf(stderr, "Discarding malformed packet (invalid group offset)\n");
        !           475:                return;
        !           476:        }
        !           477: 
        !           478:        offset = sizeof(*grp);
        !           479:        remaining = grpoffset - offset;
        !           480: 
        !           481:        while (remaining > 0) {
        !           482:                struct distr_msg_item *intf = (struct distr_msg_item *) (((char *) grp) + offset);
        !           483:                int ioff = ntohs(intf->i_offset);
        !           484: 
        !           485:                if (ioff < (sizeof(*intf) + 4) || ioff > ntohs(hdr->h_len)) {
        !           486:                        if (c_debug)
        !           487:                                fprintf(stderr, "Discarding malformed packet (interface offset too short)\n");
        !           488:                        return;
        !           489:                }
        !           490: 
        !           491:                if (ioff > remaining) {
        !           492:                        if (c_debug)
        !           493:                                fprintf(stderr, "Discarding malformed packet (unexpected group end)\n");
        !           494:                        return;
        !           495:                }
        !           496: 
        !           497:                if (process_item(hdr, nodename, intf, from) < 0)
        !           498:                        return;
        !           499: 
        !           500:                remaining -= ioff;
        !           501:                offset += ioff;
        !           502:        }
        !           503: 
        !           504:        if (remaining < 0)
        !           505:                if (c_debug)
        !           506:                        fprintf(stderr, "Leftover from group: %d\n", abs(remaining));
        !           507: }
        !           508: 
        !           509: static void process_msg(struct distr_msg_hdr *hdr, char *from)
        !           510: {
        !           511:        char *nodename;
        !           512:        struct distr_msg_grp *group;
        !           513:        
        !           514:        if (c_debug)
        !           515:                fprintf(stderr, "Processing message from %s (len=%d)\n",
        !           516:                        from, ntohs(hdr->h_len));
        !           517: 
        !           518:        nodename = ((char *) hdr) + sizeof(*hdr);
        !           519:        group = (struct distr_msg_grp *) (((char *) hdr) + hdr->h_offset);
        !           520: 
        !           521:        if ('\0' == *nodename) {
        !           522:                if (c_debug)
        !           523:                        fprintf(stderr, "Discarding malformed packet (empty nodename)\n");
        !           524:                return;
        !           525:        }
        !           526:                
        !           527: 
        !           528:        process_group(hdr, nodename, group, from);
        !           529: }
        !           530: 
        !           531: static void process_data(char *buf, int len, char *from)
        !           532: {
        !           533:        struct distr_msg_hdr *hdr = (struct distr_msg_hdr *) buf;
        !           534: 
        !           535:        if (len < sizeof(*hdr)) {
        !           536:                if (c_debug)
        !           537:                        fprintf(stderr, "Discarding malformed packet (hdrcheck)\n");
        !           538:                return;
        !           539:        }
        !           540: 
        !           541:        if (hdr->h_magic != BMON_MAGIC) {
        !           542:                if (c_debug)
        !           543:                        fprintf(stderr, "Discarding malformed packet (magic mismatch)\n");
        !           544:                return;
        !           545:        }
        !           546: 
        !           547:        if (hdr->h_ver != BMON_VERSION) {
        !           548:                if (c_debug)
        !           549:                        fprintf(stderr, "Discarding incompatible packet (version mismatch)\n");
        !           550:                return;
        !           551:        }
        !           552: 
        !           553:        if (ntohs(hdr->h_len) < len) {
        !           554:                if (c_debug)
        !           555:                        fprintf(stderr, "Discarding malformed packet (packet size mismatch)\n");
        !           556:                return;
        !           557:        }
        !           558: 
        !           559:        if (hdr->h_offset < (sizeof(*hdr) + 4)) {
        !           560:                if (c_debug)
        !           561:                        fprintf(stderr, "Discarding malformed packet (offset too short)\n");
        !           562:                return;
        !           563:        }
        !           564: 
        !           565:        process_msg(hdr, from);
        !           566: }
        !           567: 
        !           568: static void distribution_read(void)
        !           569: {
        !           570:        int i, n;
        !           571:        struct sockaddr_in6 addr;
        !           572:        socklen_t len = sizeof(addr);
        !           573:        char addrstr[INET6_ADDRSTRLEN];
        !           574: 
        !           575:        memset(&addr, 0, sizeof(addr));
        !           576:        memset(buf, 0, c_bufsize);
        !           577: 
        !           578:        for (i = 0; i < c_max_read; i++) {
        !           579:                n = recvfrom(recv_fd, buf, c_bufsize, 0,
        !           580:                        (struct sockaddr *) &addr, &len);
        !           581: 
        !           582:                if (n < 0) {
        !           583:                        if (EAGAIN == errno)
        !           584:                                return;
        !           585:                        else
        !           586:                                quit("recvfrom failed: %s\n", strerror(errno));
        !           587:                }
        !           588: 
        !           589:                if (addr.sin6_family == AF_INET) {
        !           590:                        struct sockaddr_in *in4 = (struct sockaddr_in *) &addr;
        !           591:                        inet_ntop(AF_INET, (void *) &in4->sin_addr,
        !           592:                                addrstr, len);
        !           593:                } else if (addr.sin6_family == AF_INET6) {
        !           594:                        inet_ntop(AF_INET6, (void *) &addr.sin6_addr,
        !           595:                                addrstr, len);
        !           596:                }
        !           597: 
        !           598:                if (c_debug)
        !           599:                        fprintf(stderr, "Read %d bytes from %s\n", n, addrstr);
        !           600: 
        !           601:                process_data(buf, n, addrstr);
        !           602:        }
        !           603: 
        !           604:        return;
        !           605: }
        !           606: 
        !           607: static void distribution_init(void)
        !           608: {
        !           609:        buf = xcalloc(1, c_bufsize);
        !           610: }
        !           611: 
        !           612: static void print_help(void)
        !           613: {
        !           614:        printf(
        !           615:        "Distribution - Collects statistics from other nodes\n" \
        !           616:        "\n" \
        !           617:        "  Collects statistics from other nodes using the distribution\n" \
        !           618:        "  secondary output method (-O distribution).\n" \
        !           619:        "\n" \
        !           620:        "  Author: Thomas Graf <tgraf@suug.ch>\n" \
        !           621:        "\n" \
        !           622:        "  Options:\n" \
        !           623:        "    ip=ADDR            Only process messages from this address (default: none)\n" \
        !           624:        "    port=NUM           Port the messages are comming from (default: 2048)\n" \
        !           625:        "    ipv6               Prefer IPv6 when creating sockets\n" \
        !           626:        "    multicast[=ADDR]   Use multicast to collect statistics\n" \
        !           627:        "    intf=NAME          Bind multicast socket to given interface\n" \
        !           628:        "    nobind             Don't bind, receive multicast and unicast messages\n" \
        !           629:        "    max_read=NUM       Max. reads during one read interval (default: 10)\n" \
        !           630:        "    bufsize=NUM        Size of receive buffer (default: 8192)\n" \
        !           631:        "    debug              Print verbose message for debugging\n" \
        !           632:        "    help               Print this help text\n");
        !           633: }
        !           634: 
        !           635: static void distribution_set_opts(tv_t *attrs)
        !           636: {
        !           637:        while (attrs) {
        !           638:                if (!strcasecmp(attrs->type, "port") && attrs->value) {
        !           639:                        c_port = attrs->value;
        !           640:                        c_port_int = strtol(c_port, NULL, 0);
        !           641:                } else if (!strcasecmp(attrs->type, "ip") && attrs->value)
        !           642:                        c_ip = attrs->value;
        !           643:                else if (!strcasecmp(attrs->type, "ipv6"))
        !           644:                        c_ipv6 = 1;
        !           645:                else if (!strcasecmp(attrs->type, "max_read") && attrs->value)
        !           646:                        c_max_read = strtol(attrs->value, NULL, 0);
        !           647:                else if (!strcasecmp(attrs->type, "bufsize") && attrs->value)
        !           648:                        c_bufsize = strtol(attrs->value, NULL, 0);
        !           649:                else if (!strcasecmp(attrs->type, "debug"))
        !           650:                        c_debug = 1;
        !           651:                else if (!strcasecmp(attrs->type, "multicast")) {
        !           652:                        if (attrs->value)
        !           653:                                c_ip = attrs->value;
        !           654:                        else
        !           655:                                c_ip = "224.0.0.1";
        !           656:                } else if (!strcasecmp(attrs->type, "nobind"))
        !           657:                        c_bind = 0;
        !           658:                else if (!strcasecmp(attrs->type, "intf") && attrs->value)
        !           659:                        c_iface = attrs->value;
        !           660:                else if (!strcasecmp(attrs->type, "help")) {
        !           661:                        print_help();
        !           662:                        exit(0);
        !           663:                }
        !           664:                attrs = attrs->next;
        !           665:        }
        !           666: }
        !           667: 
        !           668: static struct input_module distribution_ops = {
        !           669:        .im_name = "distribution",
        !           670:        .im_set_opts = distribution_set_opts,
        !           671:        .im_read = distribution_read,
        !           672:        .im_probe = distribution_probe,
        !           673:        .im_init = distribution_init,
        !           674: };
        !           675: 
        !           676: static void __init do_distribution_init(void)
        !           677: {
        !           678:        register_secondary_input_module(&distribution_ops);
        !           679: }

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