Commit dc695488 authored by Arne Øslebø's avatar Arne Øslebø

First import

git-svn-id: file:///home/svn/ssmping/trunk@1 be536cd1-dada-44cd-b178-a1c9df5b8ff3
parents
PREFIX ?= /usr/local
all: ssmping asmping ssmpingd mcfirst
OBJ = ssmpngcl.o ssmpingc.o
ssmping: $(OBJ) joinch.o
asmping: $(OBJ) joingrp.o
mcfirst: $(OBJ) joinch.o joingrp.o
ssmpingd: $(OBJ)
install: ssmping asmping ssmpingd mcfirst
install -D ssmping $(DESTDIR)$(PREFIX)/bin/ssmping
install -D asmping $(DESTDIR)$(PREFIX)/bin/asmping
install -D ssmpingd $(DESTDIR)$(PREFIX)/bin/ssmpingd
install -D mcfirst $(DESTDIR)$(PREFIX)/bin/mcfirst
install -D ssmping.1 $(DESTDIR)$(PREFIX)/man/man1/ssmping.1
install -D asmping.1 $(DESTDIR)$(PREFIX)/man/man1/asmping.1
install -D mcfirst.1 $(DESTDIR)$(PREFIX)/man/man1/mcfirst.1
clean:
rm -f $(OBJ) joinch.o joingrp.o ssmping asmping ssmpingd mcfirst
PREFIX ?= /usr/local
all: ssmping asmping ssmpingd mcfirst
OBJ = ssmpngcl.o ssmpingc.o joinch.o joingrp.o
ssmping: $(OBJ)
$(CC) $(CFLAGS) $(OBJ) -o ssmping ssmping.c
asmping: $(OBJ)
$(CC) $(CFLAGS) $(OBJ) -o asmping asmping.c
ssmpingd: $(OBJ)
$(CC) $(CFLAGS) $(OBJ) -o ssmpingd ssmpingd.c
mcfirst: $(OBJ)
$(CC) $(CFLAGS) $(OBJ) -o mcfirst mcfirst.c
install: ssmping asmping ssmpingd mcfirst
install -D ssmping $(DESTDIR)$(PREFIX)/bin/ssmping
install -D asmping $(DESTDIR)$(PREFIX)/bin/asmping
install -D ssmpingd $(DESTDIR)$(PREFIX)/bin/ssmpingd
install -D mcfirst $(DESTDIR)$(PREFIX)/bin/mcfirst
install -D ssmping.1 $(DESTDIR)$(PREFIX)/man/man1/ssmping.1
install -D asmping.1 $(DESTDIR)$(PREFIX)/man/man1/asmping.1
install -D mcfirst.1 $(DESTDIR)$(PREFIX)/man/man1/mcfirst.1
clean:
rm -f $(OBJ) ssmping asmping ssmpingd mcfirst
PREFIX ?= /usr/local
LDFLAGS ?= -lsocket -lnsl
all: ssmping asmping ssmpingd mcfirst
OBJ = ssmpngcl.o ssmpingc.o
ssmping: $(OBJ) joinch.o
asmping: $(OBJ) joingrp.o
ssmpingd: $(OBJ)
mcfirst: $(OBJ) joinch.o joingrp.o
install: ssmping asmping ssmpingd mcfirst
install -D ssmping $(DESTDIR)$(PREFIX)/bin/ssmping
install -D asmping $(DESTDIR)$(PREFIX)/bin/asmping
install -D mcfirst $(DESTDIR)$(PREFIX)/bin/mcfirst
install -D ssmpingd $(DESTDIR)$(PREFIX)/bin/ssmpingd
install -D ssmping.1 $(DESTDIR)$(PREFIX)/man/man1/ssmping.1
install -D asmping.1 $(DESTDIR)$(PREFIX)/man/man1/asmping.1
install -D mcfirst.1 $(DESTDIR)$(PREFIX)/man/man1/mcfirst.1
clean:
rm -f $(OBJ) ssmping asmping ssmpingd mcfirst
PREFIX ?= /usr/local
CFLAGS ?= -D_POSIX_C_SOURCE -D__EXTENSIONS__ -D_XPG4_2
LDFLAGS ?= -lsocket -lnsl
all: asmping ssmpingd mcfirst
OBJ = ssmpngcl.o ssmpingc.o
ssmping: $(OBJ) joinch.o
asmping: $(OBJ) joingrp.o
ssmpingd: $(OBJ)
mcfirst: $(OBJ) joinch.o joingrp.o
install: asmping ssmpingd mcfirst
install -D asmping $(DESTDIR)$(PREFIX)/bin/asmping
install -D ssmpingd $(DESTDIR)$(PREFIX)/bin/ssmpingd
install -D mcfirst $(DESTDIR)$(PREFIX)/bin/mcfirst
install -D asmping.1 $(DESTDIR)$(PREFIX)/man/man1/asmping.1
install -D mcfirst.1 $(DESTDIR)$(PREFIX)/man/man1/mcfirst.1
clean:
rm -f $(OBJ) joinch.o joingrp.o asmping ssmpingd mcfirst
CC=/opt/xmingw/bin/i386-mingw32msvc-gcc
CFLAGS=-Wall -I/opt/xmingw/i386-mingw32msvc/include
LIBPATH = /opt/xmingw/i386-mingw32msvc/lib
OBJ = ssmpngcl.o ssmpingc.o
all: ssmping asmping ssmpingd mcfirst
ssmping: $(OBJ) joinch.o $(LIBPATH)/libwsock32.a $(LIBPATH)/libws2_32.a $(LIBPATH)/libdnsapi.a
asmping: $(OBJ) joingrp.o $(LIBPATH)/libwsock32.a $(LIBPATH)/libws2_32.a $(LIBPATH)/libdnsapi.a
mcfirst: $(OBJ) joinch.o joingrp.o $(LIBPATH)/libwsock32.a $(LIBPATH)/libws2_32.a $(LIBPATH)/libdnsapi.a
ssmpingd: $(OBJ) $(LIBPATH)/libwsock32.a $(LIBPATH)/libws2_32.a $(LIBPATH)/libdnsapi.a
clean:
rm -f $(OBJ) joinch.o joingrp.o ssmping asmping ssmpingd mcfirst
install: ssmping asmping ssmpingd mcfirst
mv ssmping ssmping.exe
mv asmping asmping.exe
mv ssmpingd ssmpingd.exe
mv mcfirst mcfirst.exe
ssmping/asmping/ssmpingd/mcfirst README
Introduction
ssmping is a tool for checking whether a host can receive SSM from
another. If a host runst ssmpingd, users on other hosts can check
that they receive from this host by running the ssmping tool.
asmping is similar to ssmping, but checks for ASM rather than SSM.
This package also contains a tool called mcfirst.
How it works
ssmpingd listens for ssmping requests at UDP port 4321, both IPv4
and IPv6. ssmping is run as "ssmping host". ssmping will look up
addresses for hostname if necessary (both IPv4 and IPv6 addresses)
and then join (S,G) where S is the IP address, and G is either
232.43.211.234 for IPv4 or ff3e::4321:1234 for IPv6. Next it will
until interrupted, send a unicast UDP ping request to the host once
per second. If the host is running ssmpingd, it will respond by
sending the request packet back (only changing type from request
to reply). The reply is sent back both by unicast and to the
multicast group G that the client joined.
asmping works pretty much like ssmping, but the group to use must
be specified. Note that the group will be forced to end with 234
for IPv4, and ::4321:1234 for IPv6.
Example ssmping output:
ssmping joined (S,G) = (2001:700:1:7:290:27ff:fe22:7186,ff3e::4321:1234)
pinging S from 2001:630:d0:111:250:fcff:fe6a:42b3
unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=0 dist=20 time=56.5ms
unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=1 dist=20 time=58.6ms
unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=2 dist=20 time=57.1ms
unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=3 dist=20 time=58.5ms
unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=4 dist=20 time=74.0ms
unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=5 dist=20 time=60.7ms
unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=6 dist=20 time=56.5ms
multicast from 2001:700:1:7:290:27ff:fe22:7186, seq=6 dist=12 time=60.9ms
unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=7 dist=20 time=61.1ms
multicast from 2001:700:1:7:290:27ff:fe22:7186, seq=7 dist=12 time=64.1ms
unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=8 dist=20 time=70.9ms
multicast from 2001:700:1:7:290:27ff:fe22:7186, seq=8 dist=12 time=73.2ms
This shows that it took about 6s for the multicast tree to be
established. The first 6 multicast packets got lost. It also
shows the round-trip time for the unicast and multicat (note that
the multicast is really unicast in one direction). This shows here
that there is roughly 3-4ms additional delay for the multicat
packets. It also shows that the unicast packets have travelled 20
hops, while multicast only 12 hops. This shows that there probably
is some tunneling for multicast. This is measured by having
ssmpingd send all packets with a TTL/hop-limit of 64.
Building
On most systems you can just type "make". On Solaris or Windows
try one of the alternate Makefiles. If your system does not
support SSM, you can still use asmping and ssmpingd. If
ssmping build fails, try "make asmping" and "make ssmpingd".
Usage
ssmpingd is run without arguments. ssmping takes hostname or IP
address as argument. asmping takes group and hostname/address as
arguments. See man pages for details.
mcfirst
mcfirst is a tool to check whether you can receive a given
multicast transmission. It supports both ASM and SSM, and IPv4
and IPv6. You run it specifying multicast group (and source if
SSM) and port number. It will then run until it receives a single
multicast packet, and tell you how long it took. Optionally you
may specify how many packets and/or for how many seconds it shall
run. If you specify how long to run, it will also tell you how
many bits and packets per second were received. This tool will
be built together with the ssmping tools.
Credits
The ssmping idea was proposed by Pavan Namburi, Kamil Sarac and
Kevin C. Almeroth in the paper
http://www.utdallas.edu/~ksarac/research/publications/CIIT04-1.pdf
I was also inspired to work on this from discussions with Mickael
Hoerdt who has contributed with several ideas.
License
See top of the individual source files.
Bugs/feedback
I would be happy for any feedback.
2006-06-05 Stig Venaas <venaas@uninett.no>
.\" Copyright (C) 2005 Stig Venaas <venaas@uninett.no>
.\" $Id: asmping.1,v 1.1 2005/10/18 14:50:31 sv Exp $
.TH asmping "1" "User Manuals"
.SH NAME
asmping \- check if you can receive IPv4/IPv6 multicast data from an internet
host
.SH SYNOPSIS
.B asmping
[
.B \-46v
] [
.B \-I
.I interface
] [
.B \-c
.I count
] [
.B \-s
.I size
]
.I group
.I host
.sp
.B ssmpingd
.SH DESCRIPTION
.B asmping
and
.B ssmpingd
are network level multicast management tools that can be used to check whether
one can receive multicast packets via ASM from a host.
The host target given to
.B asmping
must run the
.B ssmpingd
daemon, which listens on UDP port
.B 4321
for IPv4 and IPv6 unicast requests.
When it receives one, it responds to the specified multicast group which
.B asmping
just have joined.
Note that one can not use arbitrary groups. Independent of what group is
specified, the last quarter of the address is forced to be
.B 234
or
.B ::4321:1234
for IPv4 or IPv6 respectively.
.SH OPTIONS
For
.B ssmpingd
there are no options.
For
.B asmping
the options are as follows.
.TP
.B \-4
Force IPv4
.TP
.B \-6
Force IPv6
.TP
.B \-v
Print client and server version information.
.TP
\fB-I\fR \fIinterface\fR
Interface to join on
.TP
\fB-c\fR \fIcount\fR
Stop after sending (and receiving)
.I count
requests (and replies)
.TP
\fB-s\fR \fIsize\fR
Request replies to have a size of
.I size
bytes
.SH SEE ALSO
ssmping(1) a tool for checking whether can receive SSM.
.TP
dbeacon(1) a distributed beacon multicast implementation.
.SH BUGS
Please report them to Stig Venaas <venaas@uninett.no>, the author of this tool.
.SH HISTORY
\fBasmping\fR and \fBssmpingd\fR were developed by Stig Venaas during the
early days of the m6bone, the IPv6 multicast backbone.
/*
* Copyright (C) 2005 Stig Venaas <venaas@uninett.no>
* $Id: asmping.c,v 1.4 2005/11/29 16:27:26 sv Exp $
*
* Contributions:
* Solaris support by Alexander Gall <gall@switch.ch>
* Initial Windows support by Nick Lamb <njl@ecs.soton.ac.uk>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*/
#include "ssmping.h"
extern int optind;
extern char *optarg;
int main(int argc, char **argv) {
int famarg, family, count, ver, us, ms;
char *pingee, *group, source[INET6_ADDRSTRLEN];
uint16_t size;
uint32_t intface;
struct sockaddr_storage name, ucaddr, mcaddr, grpaddr;
socklen_t namelen;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 2, 0 );
WSAStartup(wVersionRequested, &wsaData);
/* lots of complicated Win32 error checking expected - sigh - */
#endif
parseargs(argc, argv, ASMMODE, &famarg, &ver, &size, &intface, &count, &pingee, &group, NULL, NULL, NULL);
family = famarg;
if (names2addrsocks(&us, &ms, pingee, group, "4321", &family, &ucaddr, &mcaddr))
errx("Failed to create socket for %s", group);
prep_sock(family, us);
prep_sock(family, ms);
setvbuf(stdout, NULL, _IONBF, 0);
findsrc((struct sockaddr *)&name, (struct sockaddr *)&ucaddr);
namelen = SOCKADDR_SIZE(name);
setport((struct sockaddr *)&name, 0);
if (bind(us, (struct sockaddr *)&name, namelen) < 0)
errx("bind");
if (connect(us, (struct sockaddr *)&ucaddr, namelen) < 0)
errx("connect");
if (getsockname(us, (struct sockaddr *)&name, &namelen) == -1)
errx("getsockname");
grpaddr = name;
setaddr(&grpaddr, group ? &mcaddr : NULL, "ff3e::4321:1234", "232.43.211.234");
#ifdef WIN32
{
struct sockaddr_storage any = name;
setaddr(&any, NULL, "::", "0.0.0.0");
if (bind(ms, (struct sockaddr *)&any, namelen) < 0)
errx("bind [INADDR_ANY]");
}
#else
if (bind(ms, (struct sockaddr *)&grpaddr, namelen) < 0)
errx("bind [multicast]");
#endif
/* using name to specify interface is wrong, only problem for old API */
joingroup(ms, (struct sockaddr *)&grpaddr, intface, (struct sockaddr *)&name);
strcpy(source, addr2string((struct sockaddr *)&ucaddr, namelen));
printf("asmping joined (S,G) = (*,%s)\n",
addr2string((struct sockaddr *)&grpaddr, namelen));
printf("pinging %s from %s\n", source, addr2string((struct sockaddr *)&name, namelen));
return doit(ver, size, count, us, ms, &ucaddr, &grpaddr, source);
}
/*
* Copyright (C) 2005 Stig Venaas <venaas@uninett.no>
* $Id:$
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*/
#include "ssmping.h"
#ifndef MCAST_JOIN_SOURCE_GROUP
#ifdef WIN32 /* Only useful on Vista */
#define MCAST_JOIN_SOURCE_GROUP 45
#endif
#ifdef linux
#define MCAST_JOIN_SOURCE_GROUP 46
#endif
struct group_source_req {
uint32_t gsr_interface; /* interface index */
struct sockaddr_storage gsr_group; /* group address */
struct sockaddr_storage gsr_source; /* source address */
};
#endif
void joinchannel(int s, struct sockaddr *src, struct sockaddr *grp, uint32_t intface, struct sockaddr *ifaddr) {
#ifdef MCAST_JOIN_SOURCE_GROUP
int level;
socklen_t addrlen;
#ifdef WIN32
struct ip_mreq_source imsr;
#endif
struct group_source_req gsreq;
if (src->sa_family != grp->sa_family) {
fprintf(stderr, "joinchannel failed, source and group must be of same address family\n");
exit(1);
}
if (ifaddr && ifaddr->sa_family != grp->sa_family) {
fprintf(stderr, "joinchannel failed, group and interface must be of same address family\n");
exit(1);
}
switch (grp->sa_family) {
case AF_INET:
addrlen = sizeof(struct sockaddr_in);
level = IPPROTO_IP;
break;
case AF_INET6:
addrlen = sizeof(struct sockaddr_in6);
level = IPPROTO_IPV6;
break;
default:
fprintf(stderr, "joinchannel failed, unsupported address family\n");
exit(1);
}
memset(&gsreq, 0, sizeof(gsreq));
memcpy(&gsreq.gsr_source, src, addrlen);
memcpy(&gsreq.gsr_group, grp, addrlen);
gsreq.gsr_interface = intface;
#ifndef WIN32
if (setsockopt(s, level, MCAST_JOIN_SOURCE_GROUP, (char *)&gsreq, sizeof(gsreq)) < 0)
errx("Failed to join multicast channel");
#else
if (setsockopt(s, level, MCAST_JOIN_SOURCE_GROUP, (char *)&gsreq, sizeof(gsreq)) >= 0)
return;
if (level != IPPROTO_IP)
errx("Failed to join multicast channel");
/* For Windows XP the above setsockopt fails, below works for IPv4
* While for Windows Vista the above should work
*/
memset(&imsr, 0, sizeof(imsr));
imsr.imr_sourceaddr = ((struct sockaddr_in *)src)->sin_addr;
imsr.imr_multiaddr = ((struct sockaddr_in *)grp)->sin_addr;
imsr.imr_interface = ((struct sockaddr_in *)ifaddr)->sin_addr;
if (setsockopt(s, level, IP_ADD_SOURCE_MEMBERSHIP, (char *)&imsr, sizeof(imsr)) < 0)
errx("Failed to join multicast channel");
#endif
#else
errx("Not built with SSM support, failed to join multicast channel");
#endif
}
/*
* Copyright (C) 2005 Stig Venaas <venaas@uninett.no>
* $Id:$
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*/
#include "ssmping.h"
void joingroup(int s, struct sockaddr *grp, uint32_t intface, struct sockaddr *ifaddr) {
int e;
#ifdef MCAST_JOIN_GROUP
int level;
socklen_t addrlen;
struct group_req greq;
#endif
if (grp && ifaddr && ifaddr->sa_family != grp->sa_family) {
fprintf(stderr, "joingroup failed, group and interface must be of same address family\n");
exit(1);
}
switch (grp->sa_family) {
case AF_INET:
#ifdef MCAST_JOIN_GROUP
addrlen = sizeof(struct sockaddr_in);
level = IPPROTO_IP;
#else
{
struct ip_mreq mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.imr_multiaddr = ((struct sockaddr_in *)grp)->sin_addr;
if (ifaddr)
mreq.imr_interface = ((struct sockaddr_in *)ifaddr)->sin_addr;
e = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
}
#endif
break;
case AF_INET6:
#ifdef MCAST_JOIN_GROUP
addrlen = sizeof(struct sockaddr_in6);
level = IPPROTO_IPV6;
#else
{
struct ipv6_mreq mreq6;
memset(&mreq6, 0, sizeof(mreq6));
mreq6.ipv6mr_multiaddr = ((struct sockaddr_in6 *)grp)->sin6_addr;
mreq6.ipv6mr_interface = intface;
e = setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6));
}
#endif
break;
default:
fprintf(stderr, "joingroup failed, unsupported address family\n");
exit(1);
}
#ifdef MCAST_JOIN_GROUP
memset(&greq, 0, sizeof(greq));
memcpy(&greq.gr_group, grp, addrlen);
greq.gr_interface = intface;
e = setsockopt(s, level, MCAST_JOIN_GROUP, (char *)&greq, sizeof(greq));
#endif
if (e < 0)
errx("Failed to join multicast group");
}
.\" Copyright (C) 2006 Stig Venaas <venaas@uninett.no>
.TH mcfirst "1" "User Manuals"
.SH NAME
mcfirst \- check if you can receive IPv4/IPv6 multicast
.SH SYNOPSIS
.B mcfirst
[
.B \-46vr
] [
.B \-I
.I interface
] [
.B \-c
.I count
] [
.B \-t
.I time
] [
.I source
]
.I group
.I port
.SH DESCRIPTION
.B mcfirst
can be used to check whether one can receive multicast packets from a host. The host may send any type of
multicast packets, any application, IPv4 or IPv6, ASM or SSM.
.B mcfirst
joins the specified (source) and group, and listens to the specified port.
.B mcfirst will by default exit when the first packet is received, and print how long it waited.
.SH OPTIONS
The options are as follows.
.TP
.B \-4
Force IPv4
.TP
.B \-6
Force IPv6
.TP
.B \-v
Print version
.TP
.B \-r
Print rate information only
.TP
\fB-I\fR \fIinterface\fR
Interface to join on
.TP
\fB-c\fR \fIcount\fR
Stop after receiving
.I count
packets. Default is 1 unless time limit is specified
.TP
\fB-t\fR \fItime\fR
Exit after
.I time
seconds. Default is to exit after the first packet. If both
.I count
and
.I time
are specified, mcfirst will exit as soon as one of them is satisfied.
.SH SEE ALSO
ssmping(1) a tool for checking whether can receive SSM.
.TP
dbeacon(1) a distributed beacon multicast implementation.
.SH BUGS
Please report them to Stig Venaas <venaas@uninett.no>, the author of this tool.
.SH HISTORY
\fBmcfirst\fR was developed by Stig Venaas during the
early days of the m6bone, the IPv6 multicast backbone.
/*
* Copyright (C) 2005, 2006 Stig Venaas <venaas@uninett.no>
* $Id:$
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*/
#include "ssmping.h"
extern int optind;
extern char *optarg;
int main(int argc, char **argv) {
int famarg, family, ver, s, ndesc, cnt, count, countarg;
char *addr1, *addr2, *srv, recvbuf[65535];
uint16_t runtime, rate;
uint32_t intface;
int32_t hops;
struct sockaddr_storage ucaddr, mcaddr;
size_t namelen, recvbuflen;
uint32_t firstbytes, bytes;
struct timeval now, rcvtime, firsttime, endtime, jointime, tstamp, diff;
fd_set readfds;
struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
double msecs;
gettime(&endtime);
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 2, 0 );
WSAStartup(wVersionRequested, &wsaData);
/* lots of complicated Win32 error checking expected - sigh - */
#endif
parseargs(argc, argv, FIRSTMODE, &famarg, &ver, NULL, &intface, &countarg, &addr1, &addr2, &runtime, &rate, &srv);
if (runtime)
endtime.tv_sec += runtime;
family = famarg;
/* addr2 next addr1 in order to request mc if only one arg */
if (names2addrsocks(&s, NULL, addr2, addr1, srv, &family, &ucaddr, &mcaddr)) {
if (addr2)
errx("Failed to create socket for %s %s", addr1, addr2);
else
errx("Failed to create socket for %s", addr1);
}
prep_sock(family, s);
setvbuf(stdout, NULL, _IONBF, 0);
namelen = (mcaddr.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
#ifdef WIN32
{
struct sockaddr_storage any = mcaddr;
setaddr(&any, NULL, "::", "0.0.0.0");
if (bind(s, (struct sockaddr *)&any, namelen) < 0)
errx("bind [INADDR_ANY]");
}
#else
if (bind(s, (struct sockaddr *)&mcaddr, namelen) < 0)
errx("bind [multicast]");
#endif
/* using name to specify interface is wrong, only problem for old API */
recvbuflen = sizeof(recvbuf);
if (addr2) {
joinchannel(s, (struct sockaddr *)&ucaddr, (struct sockaddr *)&mcaddr, intface, NULL);
printf("mcfirst joined (S,G) = (%s,%s)\n",
addr2string((struct sockaddr *)&ucaddr, namelen),
addr2string((struct sockaddr *)&mcaddr, namelen));
} else {
joingroup(s, (struct sockaddr *)&mcaddr, intface, NULL);
printf("mcfirst joined (*,G) = (*,%s)\n", addr2string((struct sockaddr *)&mcaddr, namelen));
}
gettime(&jointime);
if (!runtime && !countarg)
countarg = 1;
bytes = 0;
for (count = 0; !countarg || count < countarg; count++) {
for(;;) {
FD_ZERO(&readfds);
FD_SET(s, &readfds);
gettime(&now);
timediff(&diff, &now, &endtime);
ndesc = select(s + 1, &readfds, (fd_set *)0, (fd_set *)0, runtime ? &diff : NULL);
gettime(&now);
if (runtime && (timecmp(&endtime, &now) <= 0))
goto done;
if (ndesc < 1)
continue;
cnt = recvfromhopstime(s, (void *)&recvbuf, recvbuflen, 0, (struct sockaddr *)&from,
&fromlen, &hops, &tstamp, NULL);
if (cnt == -1) {
err("recv failed");
continue;
}
break;
}
rcvtime = tstamp.tv_sec ? tstamp : now;
if (!count) {
firsttime = rcvtime;
firstbytes = cnt;
}
bytes += cnt;
if (!rate) {
fromlen = from.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
timediff(&diff, &jointime, &rcvtime);
printf("Received %d bytes from %s after %ld.%03ld ms (ttl/hops %d)\n", cnt,
addr2string((struct sockaddr *) &from, fromlen),
diff.tv_sec * 1000 + diff.tv_usec / 1000, diff.tv_usec % 1000,
hops);
}
}
done:
timediff(&diff, &jointime, &rcvtime);
printf("%d bytes (payload) and %d packets received in %ld.%03ld seconds\n", bytes, count, diff.tv_sec, (diff.tv_usec + 500) / 1000);
if (count < 2)
return !count;
timediff(&diff, &firsttime, &rcvtime);
msecs = (double)diff.tv_sec * 1000 + (double)diff.tv_usec / 1000;
if (!msecs)
return !count;
bytes -= firstbytes;