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>