|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Copyright (c) 2010-2011, Red Hat, Inc.
|
|
Packit |
61cb5a |
*
|
|
Packit |
61cb5a |
* Permission to use, copy, modify, and/or distribute this software for any
|
|
Packit |
61cb5a |
* purpose with or without fee is hereby granted, provided that the above
|
|
Packit |
61cb5a |
* copyright notice and this permission notice appear in all copies.
|
|
Packit |
61cb5a |
*
|
|
Packit |
61cb5a |
* THE SOFTWARE IS PROVIDED "AS IS" AND RED HAT, INC. DISCLAIMS ALL WARRANTIES
|
|
Packit |
61cb5a |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
Packit |
61cb5a |
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RED HAT, INC. BE LIABLE
|
|
Packit |
61cb5a |
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
Packit |
61cb5a |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
Packit |
61cb5a |
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
Packit |
61cb5a |
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Author: Jan Friesse <jfriesse@redhat.com>
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#define __STDC_LIMIT_MACROS
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include <sys/types.h>
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include <netinet/in.h>
|
|
Packit |
61cb5a |
#include <arpa/inet.h>
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include <err.h>
|
|
Packit |
61cb5a |
#include <stdint.h>
|
|
Packit |
61cb5a |
#include <stdio.h>
|
|
Packit |
61cb5a |
#include <stdlib.h>
|
|
Packit |
61cb5a |
#include <string.h>
|
|
Packit |
61cb5a |
#include <unistd.h>
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include "addrfunc.h"
|
|
Packit |
61cb5a |
#include "omping.h"
|
|
Packit |
61cb5a |
#include "cli.h"
|
|
Packit |
61cb5a |
#include "logging.h"
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void conv_list_addrs(struct ai_list *ai_list, int ip_ver);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void conv_local_addr(struct ai_list *ai_list, struct ai_item *ai_local,
|
|
Packit |
61cb5a |
const struct ifaddrs *ifa_local, int ip_ver, struct ai_item *local_addr, int *single_addr);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int conv_params_ipbc(struct ai_item *ipbc_addr, const char *ipbc_addr_s,
|
|
Packit |
61cb5a |
const char *port_s, const struct ifaddrs *ifa_local);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void conv_params_mcast(int ip_ver, struct ai_item *mcast_addr, const char *mcast_addr_s,
|
|
Packit |
61cb5a |
const char *port_s);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int parse_remote_addrs(int argc, char * const argv[], const char *port, int ip_ver,
|
|
Packit |
61cb5a |
struct ai_list *ai_list);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int return_ip_ver(int ip_ver, const char *mcast_addr, const char *port,
|
|
Packit |
61cb5a |
struct ai_list *ai_list);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void show_version(void);
|
|
Packit |
61cb5a |
static void usage();
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Parse command line.
|
|
Packit |
61cb5a |
* argc and argv are passed from main function. local_ifname will be allocated and filled by name
|
|
Packit |
61cb5a |
* of local ethernet interface. ip_ver will be filled by forced ip version or will
|
|
Packit |
61cb5a |
* be 0. mcast_addr will be filled by requested mcast address or will be NULL. Port will be filled
|
|
Packit |
61cb5a |
* by requested port (string value) or will be NULL. ai_list will be initialized and requested
|
|
Packit |
61cb5a |
* hostnames will be stored there. ttl is pointer where user set TTL or default TTL will be stored.
|
|
Packit |
61cb5a |
* single_addr is boolean set if only one remote address is entered. quiet is flag for quiet mode.
|
|
Packit |
61cb5a |
* cont_stat is flag for enable continuous statistic. timeout_time is number of miliseconds after
|
|
Packit |
61cb5a |
* which client exits regardless to number of received/sent packets. wait_for_finish_time is number
|
|
Packit |
61cb5a |
* of miliseconds to wait before exit to allow other nodes not to screw up final statistics.
|
|
Packit |
61cb5a |
* dup_buf_items is number of items which should be stored in duplicate packet detection buffer.
|
|
Packit |
61cb5a |
* Default is MIN_DUP_BUF_ITEMS for intervals > 1, or DUP_BUF_SECS value divided by ping interval
|
|
Packit |
61cb5a |
* in seconds or 0, which is used for disabling duplicate detection. rate_limit_time is maximum
|
|
Packit |
61cb5a |
* time between two received packets. sndbuf_size is size of socket buffer to allocate for sending
|
|
Packit |
61cb5a |
* packets. rcvbuf_size is size of socket buffer to allocate for receiving packets. Both
|
|
Packit |
61cb5a |
* sndbuf_size and rcvbuf_size are set to 0 if user doesn't supply option. send_count_queries is by
|
|
Packit |
61cb5a |
* default set to 0, but may be overwritten by user and it means that after sending that number of
|
|
Packit |
61cb5a |
* queries, client is put to stop state. auto_exit is boolean variable which is enabled by default
|
|
Packit |
61cb5a |
* and can be disabled by -E option. If auto_exit is enabled, loop will end if every client is in
|
|
Packit |
61cb5a |
* STOP state.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
cli_parse(struct ai_list *ai_list, int argc, char * const argv[], char **local_ifname, int *ip_ver,
|
|
Packit |
61cb5a |
struct ai_item *local_addr, int *wait_time, enum sf_transport_method *transport_method,
|
|
Packit |
61cb5a |
struct ai_item *mcast_addr, uint16_t *port, uint8_t *ttl, int *single_addr, int *quiet,
|
|
Packit |
61cb5a |
int *cont_stat, int *timeout_time, int *wait_for_finish_time, int *dup_buf_items,
|
|
Packit |
61cb5a |
int *rate_limit_time, int *sndbuf_size, int *rcvbuf_size, uint64_t *send_count_queries,
|
|
Packit |
61cb5a |
int *auto_exit, enum omping_op_mode *op_mode)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct ai_item *ai_item;
|
|
Packit |
61cb5a |
struct ifaddrs *ifa_list, *ifa_local;
|
|
Packit |
61cb5a |
char *ep;
|
|
Packit |
61cb5a |
char *mcast_addr_s;
|
|
Packit |
61cb5a |
const char *port_s;
|
|
Packit |
61cb5a |
double numd;
|
|
Packit |
61cb5a |
int ch;
|
|
Packit |
61cb5a |
int force;
|
|
Packit |
61cb5a |
int num;
|
|
Packit |
61cb5a |
int res;
|
|
Packit |
61cb5a |
int rate_limit_time_set;
|
|
Packit |
61cb5a |
int show_ver;
|
|
Packit |
61cb5a |
int wait_for_finish_time_set;
|
|
Packit |
61cb5a |
unsigned int ifa_flags;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
*auto_exit = 1;
|
|
Packit |
61cb5a |
*cont_stat = 0;
|
|
Packit |
61cb5a |
*dup_buf_items = MIN_DUP_BUF_ITEMS;
|
|
Packit |
61cb5a |
*ip_ver = 0;
|
|
Packit |
61cb5a |
*local_ifname = NULL;
|
|
Packit |
61cb5a |
mcast_addr_s = NULL;
|
|
Packit |
61cb5a |
*op_mode = OMPING_OP_MODE_NORMAL;
|
|
Packit |
61cb5a |
*quiet = 0;
|
|
Packit |
61cb5a |
*send_count_queries = 0;
|
|
Packit |
61cb5a |
*sndbuf_size = 0;
|
|
Packit |
61cb5a |
*single_addr = 0;
|
|
Packit |
61cb5a |
*rate_limit_time = 0;
|
|
Packit |
61cb5a |
*rcvbuf_size = 0;
|
|
Packit |
61cb5a |
*timeout_time = 0;
|
|
Packit |
61cb5a |
*ttl = DEFAULT_TTL;
|
|
Packit |
61cb5a |
*transport_method = SF_TM_ASM;
|
|
Packit |
61cb5a |
*wait_time = DEFAULT_WAIT_TIME;
|
|
Packit |
61cb5a |
*wait_for_finish_time = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
force = 0;
|
|
Packit |
61cb5a |
ifa_flags = IFF_MULTICAST;
|
|
Packit |
61cb5a |
port_s = DEFAULT_PORT_S;
|
|
Packit |
61cb5a |
rate_limit_time_set = 0;
|
|
Packit |
61cb5a |
show_ver = 0;
|
|
Packit |
61cb5a |
wait_for_finish_time_set = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
logging_set_verbose(0);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
while ((ch = getopt(argc, argv, "46CDEFqVvc:i:M:m:O:p:R:r:S:T:t:w:")) != -1) {
|
|
Packit |
61cb5a |
switch (ch) {
|
|
Packit |
61cb5a |
case '4':
|
|
Packit |
61cb5a |
*ip_ver = 4;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case '6':
|
|
Packit |
61cb5a |
*ip_ver = 6;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'C':
|
|
Packit |
61cb5a |
(*cont_stat)++;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'D':
|
|
Packit |
61cb5a |
*dup_buf_items = 0;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'E':
|
|
Packit |
61cb5a |
*auto_exit = 0;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'F':
|
|
Packit |
61cb5a |
force++;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'q':
|
|
Packit |
61cb5a |
(*quiet)++;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'V':
|
|
Packit |
61cb5a |
show_ver++;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'v':
|
|
Packit |
61cb5a |
logging_set_verbose(logging_get_verbose() + 1);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'c':
|
|
Packit |
61cb5a |
numd = strtod(optarg, &ep);
|
|
Packit |
61cb5a |
if (numd < 1 || *ep != '\0' || numd >= ((uint64_t)~0)) {
|
|
Packit |
61cb5a |
warnx("illegal number, -c argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
*send_count_queries= (uint64_t)numd;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'i':
|
|
Packit |
61cb5a |
numd = strtod(optarg, &ep);
|
|
Packit |
61cb5a |
if (numd < 0 || *ep != '\0' || numd * 1000 > INT32_MAX) {
|
|
Packit |
61cb5a |
warnx("illegal number, -i argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
*wait_time = (int)(numd * 1000.0);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'M':
|
|
Packit |
61cb5a |
if (strcmp(optarg, "asm") == 0) {
|
|
Packit |
61cb5a |
*transport_method = SF_TM_ASM;
|
|
Packit |
61cb5a |
ifa_flags = IFF_MULTICAST;
|
|
Packit |
61cb5a |
} else if (strcmp(optarg, "ssm") == 0 && sf_is_ssm_supported()) {
|
|
Packit |
61cb5a |
*transport_method = SF_TM_SSM;
|
|
Packit |
61cb5a |
ifa_flags = IFF_MULTICAST;
|
|
Packit |
61cb5a |
} else if (strcmp(optarg, "ipbc") == 0 && sf_is_ipbc_supported()) {
|
|
Packit |
61cb5a |
*transport_method = SF_TM_IPBC;
|
|
Packit |
61cb5a |
ifa_flags = IFF_BROADCAST;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
warnx("illegal parameter, -M argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'm':
|
|
Packit |
61cb5a |
mcast_addr_s = optarg;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'O':
|
|
Packit |
61cb5a |
if (strcmp(optarg, "normal") == 0) {
|
|
Packit |
61cb5a |
*op_mode = OMPING_OP_MODE_NORMAL;
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Temporarily disabled
|
|
Packit |
61cb5a |
*
|
|
Packit |
61cb5a |
} else if (strcmp(optarg, "server") == 0) {
|
|
Packit |
61cb5a |
*op_mode = OMPING_OP_MODE_SERVER;
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
} else if (strcmp(optarg, "client") == 0) {
|
|
Packit |
61cb5a |
*op_mode = OMPING_OP_MODE_CLIENT;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
warnx("illegal parameter, -O argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'p':
|
|
Packit |
61cb5a |
port_s = optarg;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'R':
|
|
Packit |
61cb5a |
numd = strtod(optarg, &ep);
|
|
Packit |
61cb5a |
if (numd < MIN_RCVBUF_SIZE || *ep != '\0' || numd > INT32_MAX) {
|
|
Packit |
61cb5a |
warnx("illegal number, -R argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
*rcvbuf_size = (int)numd;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'r':
|
|
Packit |
61cb5a |
numd = strtod(optarg, &ep);
|
|
Packit |
61cb5a |
if (numd < 0 || *ep != '\0' || numd * 1000 > INT32_MAX) {
|
|
Packit |
61cb5a |
warnx("illegal number, -r argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
*rate_limit_time = (int)(numd * 1000.0);
|
|
Packit |
61cb5a |
rate_limit_time_set = 1;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'S':
|
|
Packit |
61cb5a |
numd = strtod(optarg, &ep);
|
|
Packit |
61cb5a |
if (numd < MIN_SNDBUF_SIZE || *ep != '\0' || numd > INT32_MAX) {
|
|
Packit |
61cb5a |
warnx("illegal number, -S argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
*sndbuf_size = (int)numd;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 't':
|
|
Packit |
61cb5a |
num = strtol(optarg, &ep, 10);
|
|
Packit |
61cb5a |
if (num <= 0 || num > ((uint8_t)~0) || *ep != '\0') {
|
|
Packit |
61cb5a |
warnx("illegal number, -t argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
*ttl = num;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'T':
|
|
Packit |
61cb5a |
numd = strtod(optarg, &ep);
|
|
Packit |
61cb5a |
if (numd < 0 || *ep != '\0' || numd * 1000 > INT32_MAX) {
|
|
Packit |
61cb5a |
warnx("illegal number, -T argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
*timeout_time = (int)(numd * 1000.0);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 'w':
|
|
Packit |
61cb5a |
numd = strtod(optarg, &ep);
|
|
Packit |
61cb5a |
if ((numd < 0 && numd != -1) || *ep != '\0' || numd * 1000 > INT32_MAX) {
|
|
Packit |
61cb5a |
warnx("illegal number, -w argument -- %s", optarg);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
wait_for_finish_time_set = 1;
|
|
Packit |
61cb5a |
*wait_for_finish_time = (int)(numd * 1000.0);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case '?':
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
argc -= optind;
|
|
Packit |
61cb5a |
argv += optind;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Param checking
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
if (show_ver == 1) {
|
|
Packit |
61cb5a |
show_version();
|
|
Packit |
61cb5a |
exit(0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (show_ver > 1) {
|
|
Packit |
61cb5a |
if (*op_mode != OMPING_OP_MODE_NORMAL) {
|
|
Packit |
61cb5a |
warnx("op_mode must be set to normal for remote version display.");
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
*op_mode = OMPING_OP_MODE_SHOW_VERSION;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (force < 1) {
|
|
Packit |
61cb5a |
if (*wait_time < DEFAULT_WAIT_TIME) {
|
|
Packit |
61cb5a |
warnx("illegal nmber, -i argument %u ms < %u ms. Use -F to force.",
|
|
Packit |
61cb5a |
*wait_time, DEFAULT_WAIT_TIME);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (*ttl < DEFAULT_TTL) {
|
|
Packit |
61cb5a |
warnx("illegal nmber, -t argument %u < %u. Use -F to force.",
|
|
Packit |
61cb5a |
*ttl, DEFAULT_TTL);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (force < 2) {
|
|
Packit |
61cb5a |
if (*wait_time == 0) {
|
|
Packit |
61cb5a |
warnx("illegal nmber, -i argument %u ms < 1 ms. Use -FF to force.",
|
|
Packit |
61cb5a |
*wait_time);
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (*transport_method == SF_TM_IPBC) {
|
|
Packit |
61cb5a |
if (*ip_ver == 6) {
|
|
Packit |
61cb5a |
warnx("illegal transport method, -M argument ipbc is mutually exclusive "
|
|
Packit |
61cb5a |
"with -6 option");
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
*ip_ver = 4;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Computed params
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
if (!wait_for_finish_time_set) {
|
|
Packit |
61cb5a |
*wait_for_finish_time = *wait_time * DEFAULT_WFF_TIME_MUL;
|
|
Packit |
61cb5a |
if (*wait_for_finish_time < DEFAULT_WAIT_TIME) {
|
|
Packit |
61cb5a |
*wait_for_finish_time = DEFAULT_WAIT_TIME;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (*wait_time == 0) {
|
|
Packit |
61cb5a |
*dup_buf_items = 0;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* + 1 is for eliminate trucate errors
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
*dup_buf_items = ((DUP_BUF_SECS * 1000) / *wait_time) + 1;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (*dup_buf_items < MIN_DUP_BUF_ITEMS) {
|
|
Packit |
61cb5a |
*dup_buf_items = MIN_DUP_BUF_ITEMS;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!rate_limit_time_set) {
|
|
Packit |
61cb5a |
*rate_limit_time = *wait_time;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
TAILQ_INIT(ai_list);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
parse_remote_addrs(argc, argv, port_s, *ip_ver, ai_list);
|
|
Packit |
61cb5a |
*ip_ver = return_ip_ver(*ip_ver, mcast_addr_s, port_s, ai_list);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (af_find_local_ai(ai_list, ip_ver, &ifa_list, &ifa_local, &ai_item, ifa_flags) < 0) {
|
|
Packit |
61cb5a |
errx(1, "Can't find local address in arguments");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Change ai_list to struct of sockaddr_storage(s)
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
conv_list_addrs(ai_list, *ip_ver);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Find local addr and copy that. Also remove that from list
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
conv_local_addr(ai_list, ai_item, ifa_local, *ip_ver, local_addr, single_addr);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Store local ifname
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
*local_ifname = strdup(ifa_local->ifa_name);
|
|
Packit |
61cb5a |
if (*local_ifname == NULL) {
|
|
Packit |
61cb5a |
errx(1, "Can't alloc memory");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (*transport_method) {
|
|
Packit |
61cb5a |
case SF_TM_ASM:
|
|
Packit |
61cb5a |
case SF_TM_SSM:
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Convert mcast addr to something useful
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
conv_params_mcast(*ip_ver, mcast_addr, mcast_addr_s, port_s);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case SF_TM_IPBC:
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Convert broadcast addr to something useful
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
res = conv_params_ipbc(mcast_addr, mcast_addr_s, port_s, ifa_local);
|
|
Packit |
61cb5a |
if (res == -1) {
|
|
Packit |
61cb5a |
warnx("illegal broadcast address, -M argument doesn't match with local"
|
|
Packit |
61cb5a |
" broadcast address");
|
|
Packit |
61cb5a |
goto error_usage_exit;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Assign port from mcast_addr
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
*port = af_sa_port(AF_CAST_SA(&mcast_addr->sas));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
freeifaddrs(ifa_list);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
error_usage_exit:
|
|
Packit |
61cb5a |
usage();
|
|
Packit |
61cb5a |
exit(1);
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
return (-1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Convert list of addrs of addrinfo to list of addrs of sockaddr_storage. This function will also
|
|
Packit |
61cb5a |
* correctly free addrinfo(s) in list.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
conv_list_addrs(struct ai_list *ai_list, int ip_ver)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct sockaddr_storage tmp_sas;
|
|
Packit |
61cb5a |
struct addrinfo *ai_i;
|
|
Packit |
61cb5a |
struct ai_item *ai_item_i;
|
|
Packit |
61cb5a |
char *hn;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
TAILQ_FOREACH(ai_item_i, ai_list, entries) {
|
|
Packit |
61cb5a |
hn = (char *)malloc(strlen(ai_item_i->host_name) + 1);
|
|
Packit |
61cb5a |
if (hn == NULL) {
|
|
Packit |
61cb5a |
errx(1, "Can't alloc memory");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(hn, ai_item_i->host_name, strlen(ai_item_i->host_name) + 1);
|
|
Packit |
61cb5a |
ai_item_i->host_name = hn;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
for (ai_i = ai_item_i->ai; ai_i != NULL; ai_i = ai_i->ai_next) {
|
|
Packit |
61cb5a |
if (af_ai_supported_ipv(ai_i) == ip_ver) {
|
|
Packit |
61cb5a |
memset(&tmp_sas, 0, sizeof(tmp_sas));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(&tmp_sas, ai_i->ai_addr, ai_i->ai_addrlen);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
freeaddrinfo(ai_item_i->ai);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(&ai_item_i->sas, &tmp_sas, sizeof(tmp_sas));
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Convert ifa_local addr to local_addr. If only one remote_host is entered, single_addr is set, if
|
|
Packit |
61cb5a |
* not then ai_local is freed and removed from list.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
conv_local_addr(struct ai_list *ai_list, struct ai_item *ai_local,
|
|
Packit |
61cb5a |
const struct ifaddrs *ifa_local, int ip_ver, struct ai_item *local_addr, int *single_addr)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
size_t addr_len;
|
|
Packit |
61cb5a |
uint16_t port;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (ifa_local->ifa_addr->sa_family) {
|
|
Packit |
61cb5a |
case AF_INET:
|
|
Packit |
61cb5a |
addr_len = sizeof(struct sockaddr_in);
|
|
Packit |
61cb5a |
port = ((struct sockaddr_in *)&ai_local->sas)->sin_port;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case AF_INET6:
|
|
Packit |
61cb5a |
addr_len = sizeof(struct sockaddr_in6);
|
|
Packit |
61cb5a |
port = ((struct sockaddr_in6 *)&ai_local->sas)->sin6_port;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
default:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Internal program error");
|
|
Packit |
61cb5a |
err(1, "Internal program error");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(&local_addr->sas, ifa_local->ifa_addr, addr_len);
|
|
Packit |
61cb5a |
local_addr->host_name = strdup(ai_local->host_name);
|
|
Packit |
61cb5a |
if (local_addr->host_name == NULL) {
|
|
Packit |
61cb5a |
err(1, "Can't alloc memory");
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (ifa_local->ifa_addr->sa_family) {
|
|
Packit |
61cb5a |
case AF_INET:
|
|
Packit |
61cb5a |
((struct sockaddr_in *)&local_addr->sas)->sin_port = port;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case AF_INET6:
|
|
Packit |
61cb5a |
((struct sockaddr_in6 *)&local_addr->sas)->sin6_port = port;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
default:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Internal program error");
|
|
Packit |
61cb5a |
err(1, "Internal program error");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
*single_addr = (TAILQ_NEXT(TAILQ_FIRST(ai_list), entries) == NULL);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!*single_addr) {
|
|
Packit |
61cb5a |
TAILQ_REMOVE(ai_list, ai_local, entries);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
free(ai_local->host_name);
|
|
Packit |
61cb5a |
free(ai_local);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Convert ipbc_addr_s to ipbc_addr ai_item.
|
|
Packit |
61cb5a |
* Function returns 0 on success, -1 if given broadcast address is not same as local interface one.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
conv_params_ipbc(struct ai_item *ipbc_addr, const char *ipbc_addr_s, const char *port_s,
|
|
Packit |
61cb5a |
const struct ifaddrs *ifa_local)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct addrinfo *ai_res, *ai_i;
|
|
Packit |
61cb5a |
char ifa_ipbc_addr_s[INET6_ADDRSTRLEN];
|
|
Packit |
61cb5a |
int ip_ver;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ip_ver = 4;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ifa_local->ifa_broadaddr == NULL) {
|
|
Packit |
61cb5a |
errx(1, "selected local interface isn't broadcast aware");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ipbc_addr_s == NULL) {
|
|
Packit |
61cb5a |
af_sa_to_str(ifa_local->ifa_broadaddr, ifa_ipbc_addr_s);
|
|
Packit |
61cb5a |
ipbc_addr_s = ifa_ipbc_addr_s;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ipbc_addr->host_name = (char *)malloc(strlen(ipbc_addr_s) + 1);
|
|
Packit |
61cb5a |
if (ipbc_addr->host_name == NULL) {
|
|
Packit |
61cb5a |
errx(1, "Can't alloc memory");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
memcpy(ipbc_addr->host_name, ipbc_addr_s, strlen(ipbc_addr_s) + 1);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ai_res = af_host_to_ai(ipbc_addr_s, port_s, ip_ver);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
for (ai_i = ai_res; ai_i != NULL; ai_i = ai_i->ai_next) {
|
|
Packit |
61cb5a |
if (af_ai_supported_ipv(ai_i) == ip_ver) {
|
|
Packit |
61cb5a |
memcpy(&ipbc_addr->sas, ai_i->ai_addr, ai_i->ai_addrlen);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ai_i == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Internal program error");
|
|
Packit |
61cb5a |
err(1, "Internal program error");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
freeaddrinfo(ai_res);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Test if interface broadcast addr is same as returned broadcast addr
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
if (!af_sockaddr_eq(ifa_local->ifa_broadaddr, AF_CAST_SA(&ipbc_addr->sas))) {
|
|
Packit |
61cb5a |
return (-1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Convert mcast_addr_s to mcast_addr ai_item
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
conv_params_mcast(int ip_ver, struct ai_item *mcast_addr, const char *mcast_addr_s,
|
|
Packit |
61cb5a |
const char *port_s)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct addrinfo *ai_res, *ai_i;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (mcast_addr_s == NULL) {
|
|
Packit |
61cb5a |
switch (ip_ver) {
|
|
Packit |
61cb5a |
case 4:
|
|
Packit |
61cb5a |
mcast_addr_s = DEFAULT_MCAST4_ADDR;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case 6:
|
|
Packit |
61cb5a |
mcast_addr_s = DEFAULT_MCAST6_ADDR;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
default:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Internal program error");
|
|
Packit |
61cb5a |
err(1, "Internal program error");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
mcast_addr->host_name = (char *)malloc(strlen(mcast_addr_s) + 1);
|
|
Packit |
61cb5a |
if (mcast_addr->host_name == NULL) {
|
|
Packit |
61cb5a |
errx(1, "Can't alloc memory");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
memcpy(mcast_addr->host_name, mcast_addr_s, strlen(mcast_addr_s) + 1);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ai_res = af_host_to_ai(mcast_addr_s, port_s, ip_ver);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
for (ai_i = ai_res; ai_i != NULL; ai_i = ai_i->ai_next) {
|
|
Packit |
61cb5a |
if (af_ai_supported_ipv(ai_i) == ip_ver) {
|
|
Packit |
61cb5a |
memcpy(&mcast_addr->sas, ai_i->ai_addr, ai_i->ai_addrlen);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ai_i == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Internal program error");
|
|
Packit |
61cb5a |
err(1, "Internal program error");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
freeaddrinfo(ai_res);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Test if addr is really multicast
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
if (!af_is_sa_mcast(AF_CAST_SA(&mcast_addr->sas))) {
|
|
Packit |
61cb5a |
errx(1, "Given address %s is not valid multicast address", mcast_addr_s);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Parse remote addresses. Return list of addresses taken from cli
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
parse_remote_addrs(int argc, char * const argv[], const char *port, int ip_ver,
|
|
Packit |
61cb5a |
struct ai_list *ai_list)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct addrinfo *ai_res;
|
|
Packit |
61cb5a |
struct ai_item *ai_item;
|
|
Packit |
61cb5a |
int no_ai;
|
|
Packit |
61cb5a |
int i;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
no_ai = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
for (i = 0; i < argc; i++) {
|
|
Packit |
61cb5a |
ai_res = af_host_to_ai(argv[i], port, ip_ver);
|
|
Packit |
61cb5a |
if (!af_is_ai_in_list(ai_res, ai_list)) {
|
|
Packit |
61cb5a |
if (af_ai_deep_is_loopback(ai_res)) {
|
|
Packit |
61cb5a |
errx(1,"Address %s looks like loopback. Loopback ping is not "
|
|
Packit |
61cb5a |
"supported", argv[i]);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ai_item = (struct ai_item *)malloc(sizeof(struct ai_item));
|
|
Packit |
61cb5a |
if (ai_item == NULL) {
|
|
Packit |
61cb5a |
errx(1, "Can't alloc memory");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memset(ai_item, 0, sizeof(struct ai_item));
|
|
Packit |
61cb5a |
ai_item->ai = ai_res;
|
|
Packit |
61cb5a |
ai_item->host_name = argv[i];
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
TAILQ_INSERT_TAIL(ai_list, ai_item, entries);
|
|
Packit |
61cb5a |
DEBUG_PRINTF("new address \"%s\" added to list (position %d)", argv[i],
|
|
Packit |
61cb5a |
no_ai);
|
|
Packit |
61cb5a |
no_ai++;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
freeaddrinfo(ai_res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (no_ai < 1) {
|
|
Packit |
61cb5a |
warnx("at least one remote addresses should be specified");
|
|
Packit |
61cb5a |
usage();
|
|
Packit |
61cb5a |
exit(1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (no_ai);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Return ip version to use. Algorithm is following:
|
|
Packit |
61cb5a |
* - If user forced ip version, we will return that one.
|
|
Packit |
61cb5a |
* - If user entered mcast addr, we will look, what it supports
|
|
Packit |
61cb5a |
* - if only one version is supported, we will return that version
|
|
Packit |
61cb5a |
* - otherwise walk addresses and find out, what they support
|
|
Packit |
61cb5a |
* - test if every addresses support all versions.
|
|
Packit |
61cb5a |
* - If not, test that version for every other addresses
|
|
Packit |
61cb5a |
* - if all of them support that version -> return that version
|
|
Packit |
61cb5a |
* - if not -> return error
|
|
Packit |
61cb5a |
* - otherwise return 0 (item in find_local_addrinfo will be used but preferably ipv6)
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
return_ip_ver(int ip_ver, const char *mcast_addr, const char *port, struct ai_list *ai_list)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct addrinfo *ai_res;
|
|
Packit |
61cb5a |
struct ai_item *aip;
|
|
Packit |
61cb5a |
int mcast_ipver;
|
|
Packit |
61cb5a |
int ipver_res, ipver_res2;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ip_ver != 0) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("user forced forced ip_ver is %d, using that", ip_ver);
|
|
Packit |
61cb5a |
return (ip_ver);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (mcast_addr != NULL) {
|
|
Packit |
61cb5a |
ai_res = af_host_to_ai(mcast_addr, port, ip_ver);
|
|
Packit |
61cb5a |
mcast_ipver = af_ai_deep_supported_ipv(ai_res);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
DEBUG2_PRINTF("mcast_ipver for %s is %d", mcast_addr, mcast_ipver);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
freeaddrinfo(ai_res);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (mcast_ipver == -1) {
|
|
Packit |
61cb5a |
errx(1, "Mcast address %s doesn't support ipv4 or ipv6", mcast_addr);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (mcast_ipver != 0) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("mcast address for %s supports only ipv%d, using that",
|
|
Packit |
61cb5a |
mcast_addr, mcast_ipver);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Walk thru all addresses to find out, what it supports
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
TAILQ_FOREACH(aip, ai_list, entries) {
|
|
Packit |
61cb5a |
ipver_res = af_ai_deep_supported_ipv(aip->ai);
|
|
Packit |
61cb5a |
DEBUG2_PRINTF("ipver for %s is %d", aip->host_name, ipver_res);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ipver_res == -1) {
|
|
Packit |
61cb5a |
errx(1, "Host %s doesn't support ipv4 or ipv6",
|
|
Packit |
61cb5a |
aip->host_name);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ipver_res != 0 && ipver_res != mcast_ipver) {
|
|
Packit |
61cb5a |
errx(1, "Multicast address is ipv%d but host %s supports"
|
|
Packit |
61cb5a |
" only ipv%d", mcast_ipver, aip->host_name, ipver_res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (mcast_ipver);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ipver_res = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Walk thru all addresses to find out, what it supports
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
TAILQ_FOREACH(aip, ai_list, entries) {
|
|
Packit |
61cb5a |
ipver_res = af_ai_deep_supported_ipv(aip->ai);
|
|
Packit |
61cb5a |
DEBUG2_PRINTF("ipver for %s is %d", aip->host_name, ipver_res);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ipver_res == -1) {
|
|
Packit |
61cb5a |
errx(1, "Host %s doesn't support ipv4 or ipv6", aip->host_name);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ipver_res != 0) {
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ipver_res == 0) {
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Every address support every version
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Every address support all IP versions");
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ipver_res != 0) {
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Host supports only one version.
|
|
Packit |
61cb5a |
* Test availability for that version on all hosts
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
TAILQ_FOREACH(aip, ai_list, entries) {
|
|
Packit |
61cb5a |
ipver_res2 = af_ai_deep_supported_ipv(aip->ai);
|
|
Packit |
61cb5a |
DEBUG2_PRINTF("ipver for %s is %d", aip->host_name, ipver_res2);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ipver_res2 == -1) {
|
|
Packit |
61cb5a |
errx(1, "Host %s doesn't support ipv4 or ipv6", aip->host_name);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ipver_res2 != 0 && ipver_res2 != ipver_res) {
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Host doesn't support ip version of other members
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
errx(1, "Host %s doesn't support IP version %d", aip->host_name,
|
|
Packit |
61cb5a |
ipver_res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Every address support ipv%d", ipver_res);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ipver_res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Show application version
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
show_version(void)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("%s version %s\n", PROGRAM_NAME, PROGRAM_VERSION);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Display application ussage
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
usage()
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("usage: %s [-46CDEFqVv] [-c count] [-i interval] [-M transport_method]\n",
|
|
Packit |
61cb5a |
PROGRAM_NAME);
|
|
Packit |
61cb5a |
printf("%14s[-m mcast_addr] [-O op_mode] [-p port] [-R rcvbuf] [-r rate_limit]\n", "");
|
|
Packit |
61cb5a |
printf("%14s[-S sndbuf] [-T timeout] [-t ttl] [-w wait_time] remote_addr...\n", "");
|
|
Packit |
61cb5a |
}
|