xref: /minix3/tests/net/mcast/mcast.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: mcast.c,v 1.3 2015/05/28 10:19:17 ozaki-r Exp $	*/
2*0a6a1f1dSLionel Sambuc 
3*0a6a1f1dSLionel Sambuc /*-
4*0a6a1f1dSLionel Sambuc  * Copyright (c) 2014 The NetBSD Foundation, Inc.
5*0a6a1f1dSLionel Sambuc  * All rights reserved.
6*0a6a1f1dSLionel Sambuc  *
7*0a6a1f1dSLionel Sambuc  * This code is derived from software contributed to The NetBSD Foundation
8*0a6a1f1dSLionel Sambuc  * by Christos Zoulas.
9*0a6a1f1dSLionel Sambuc  *
10*0a6a1f1dSLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11*0a6a1f1dSLionel Sambuc  * modification, are permitted provided that the following conditions
12*0a6a1f1dSLionel Sambuc  * are met:
13*0a6a1f1dSLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
14*0a6a1f1dSLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
15*0a6a1f1dSLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16*0a6a1f1dSLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17*0a6a1f1dSLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18*0a6a1f1dSLionel Sambuc  *
19*0a6a1f1dSLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*0a6a1f1dSLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*0a6a1f1dSLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*0a6a1f1dSLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*0a6a1f1dSLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*0a6a1f1dSLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*0a6a1f1dSLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*0a6a1f1dSLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*0a6a1f1dSLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*0a6a1f1dSLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*0a6a1f1dSLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
30*0a6a1f1dSLionel Sambuc  */
31*0a6a1f1dSLionel Sambuc #include <sys/cdefs.h>
32*0a6a1f1dSLionel Sambuc #ifdef __RCSID
33*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: mcast.c,v 1.3 2015/05/28 10:19:17 ozaki-r Exp $");
34*0a6a1f1dSLionel Sambuc #else
35*0a6a1f1dSLionel Sambuc extern const char *__progname;
36*0a6a1f1dSLionel Sambuc #define getprogname() __progname
37*0a6a1f1dSLionel Sambuc #endif
38*0a6a1f1dSLionel Sambuc 
39*0a6a1f1dSLionel Sambuc #include <sys/types.h>
40*0a6a1f1dSLionel Sambuc #include <sys/socket.h>
41*0a6a1f1dSLionel Sambuc #include <sys/wait.h>
42*0a6a1f1dSLionel Sambuc #include <sys/time.h>
43*0a6a1f1dSLionel Sambuc #include <netinet/in.h>
44*0a6a1f1dSLionel Sambuc 
45*0a6a1f1dSLionel Sambuc #include <assert.h>
46*0a6a1f1dSLionel Sambuc #include <netdb.h>
47*0a6a1f1dSLionel Sambuc #include <time.h>
48*0a6a1f1dSLionel Sambuc #include <signal.h>
49*0a6a1f1dSLionel Sambuc #include <stdio.h>
50*0a6a1f1dSLionel Sambuc #include <string.h>
51*0a6a1f1dSLionel Sambuc #include <stdlib.h>
52*0a6a1f1dSLionel Sambuc #include <unistd.h>
53*0a6a1f1dSLionel Sambuc #include <err.h>
54*0a6a1f1dSLionel Sambuc #include <errno.h>
55*0a6a1f1dSLionel Sambuc #include <poll.h>
56*0a6a1f1dSLionel Sambuc #include <stdbool.h>
57*0a6a1f1dSLionel Sambuc 
58*0a6a1f1dSLionel Sambuc #ifdef ATF
59*0a6a1f1dSLionel Sambuc #include <atf-c.h>
60*0a6a1f1dSLionel Sambuc 
61*0a6a1f1dSLionel Sambuc #define ERRX(ev, msg, ...)	ATF_REQUIRE_MSG(0, msg, __VA_ARGS__)
62*0a6a1f1dSLionel Sambuc #define ERRX0(ev, msg)		ATF_REQUIRE_MSG(0, msg)
63*0a6a1f1dSLionel Sambuc 
64*0a6a1f1dSLionel Sambuc #define SKIPX(ev, msg, ...)	do {			\
65*0a6a1f1dSLionel Sambuc 	atf_tc_skip(msg, __VA_ARGS__);			\
66*0a6a1f1dSLionel Sambuc 	return;						\
67*0a6a1f1dSLionel Sambuc } while(/*CONSTCOND*/0)
68*0a6a1f1dSLionel Sambuc 
69*0a6a1f1dSLionel Sambuc #else
70*0a6a1f1dSLionel Sambuc #define ERRX(ev, msg, ...)	errx(ev, msg, __VA_ARGS__)
71*0a6a1f1dSLionel Sambuc #define ERRX0(ev, msg)		errx(ev, msg)
72*0a6a1f1dSLionel Sambuc #define SKIPX(ev, msg, ...)	errx(ev, msg, __VA_ARGS__)
73*0a6a1f1dSLionel Sambuc #endif
74*0a6a1f1dSLionel Sambuc 
75*0a6a1f1dSLionel Sambuc static int debug;
76*0a6a1f1dSLionel Sambuc 
77*0a6a1f1dSLionel Sambuc #define TOTAL 10
78*0a6a1f1dSLionel Sambuc #define PORT_V4MAPPED "6666"
79*0a6a1f1dSLionel Sambuc #define HOST_V4MAPPED "::FFFF:239.1.1.1"
80*0a6a1f1dSLionel Sambuc #define PORT_V4 "6666"
81*0a6a1f1dSLionel Sambuc #define HOST_V4 "239.1.1.1"
82*0a6a1f1dSLionel Sambuc #define PORT_V6 "6666"
83*0a6a1f1dSLionel Sambuc #define HOST_V6 "FF05:1:0:0:0:0:0:1"
84*0a6a1f1dSLionel Sambuc 
85*0a6a1f1dSLionel Sambuc struct message {
86*0a6a1f1dSLionel Sambuc 	size_t seq;
87*0a6a1f1dSLionel Sambuc 	struct timespec ts;
88*0a6a1f1dSLionel Sambuc };
89*0a6a1f1dSLionel Sambuc 
90*0a6a1f1dSLionel Sambuc static int
addmc(int s,struct addrinfo * ai,bool bug)91*0a6a1f1dSLionel Sambuc addmc(int s, struct addrinfo *ai, bool bug)
92*0a6a1f1dSLionel Sambuc {
93*0a6a1f1dSLionel Sambuc 	struct ip_mreq m4;
94*0a6a1f1dSLionel Sambuc 	struct ipv6_mreq m6;
95*0a6a1f1dSLionel Sambuc 	struct sockaddr_in *s4;
96*0a6a1f1dSLionel Sambuc 	struct sockaddr_in6 *s6;
97*0a6a1f1dSLionel Sambuc 	unsigned int ifc;
98*0a6a1f1dSLionel Sambuc 
99*0a6a1f1dSLionel Sambuc 	switch (ai->ai_family) {
100*0a6a1f1dSLionel Sambuc 	case AF_INET:
101*0a6a1f1dSLionel Sambuc 		s4 = (void *)ai->ai_addr;
102*0a6a1f1dSLionel Sambuc 		assert(sizeof(*s4) == ai->ai_addrlen);
103*0a6a1f1dSLionel Sambuc 		m4.imr_multiaddr = s4->sin_addr;
104*0a6a1f1dSLionel Sambuc 		m4.imr_interface.s_addr = htonl(INADDR_ANY);
105*0a6a1f1dSLionel Sambuc 		return setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
106*0a6a1f1dSLionel Sambuc 		    &m4, sizeof(m4));
107*0a6a1f1dSLionel Sambuc 	case AF_INET6:
108*0a6a1f1dSLionel Sambuc 		s6 = (void *)ai->ai_addr;
109*0a6a1f1dSLionel Sambuc 		/*
110*0a6a1f1dSLionel Sambuc 		 * Linux:	Does not support the v6 ioctls on v4 mapped
111*0a6a1f1dSLionel Sambuc 		 *		sockets but it does support the v4 ones and
112*0a6a1f1dSLionel Sambuc 		 *		it works.
113*0a6a1f1dSLionel Sambuc 		 * MacOS/X:	Supports the v6 ioctls on v4 mapped sockets,
114*0a6a1f1dSLionel Sambuc 		 *		but does not work and also does not support
115*0a6a1f1dSLionel Sambuc 		 *		the v4 ioctls. So no way to make multicasting
116*0a6a1f1dSLionel Sambuc 		 *		work with mapped addresses.
117*0a6a1f1dSLionel Sambuc 		 * NetBSD:	Supports both and works for both.
118*0a6a1f1dSLionel Sambuc 		 */
119*0a6a1f1dSLionel Sambuc 		if (bug && IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) {
120*0a6a1f1dSLionel Sambuc 			memcpy(&m4.imr_multiaddr, &s6->sin6_addr.s6_addr[12],
121*0a6a1f1dSLionel Sambuc 			    sizeof(m4.imr_multiaddr));
122*0a6a1f1dSLionel Sambuc 			m4.imr_interface.s_addr = htonl(INADDR_ANY);
123*0a6a1f1dSLionel Sambuc 			return setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
124*0a6a1f1dSLionel Sambuc 			    &m4, sizeof(m4));
125*0a6a1f1dSLionel Sambuc 		}
126*0a6a1f1dSLionel Sambuc 		assert(sizeof(*s6) == ai->ai_addrlen);
127*0a6a1f1dSLionel Sambuc 		memset(&m6, 0, sizeof(m6));
128*0a6a1f1dSLionel Sambuc #if 0
129*0a6a1f1dSLionel Sambuc 		ifc = 1;
130*0a6a1f1dSLionel Sambuc 		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
131*0a6a1f1dSLionel Sambuc 		    &ifc, sizeof(ifc)) == -1)
132*0a6a1f1dSLionel Sambuc 			return -1;
133*0a6a1f1dSLionel Sambuc 		ifc = 224;
134*0a6a1f1dSLionel Sambuc 		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
135*0a6a1f1dSLionel Sambuc 		    &ifc, sizeof(ifc)) == -1)
136*0a6a1f1dSLionel Sambuc 			return -1;
137*0a6a1f1dSLionel Sambuc 		ifc = 1; /* XXX should pick a proper interface */
138*0a6a1f1dSLionel Sambuc 		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifc,
139*0a6a1f1dSLionel Sambuc 		    sizeof(ifc)) == -1)
140*0a6a1f1dSLionel Sambuc 			return -1;
141*0a6a1f1dSLionel Sambuc #else
142*0a6a1f1dSLionel Sambuc 		ifc = 0; /* Let pick an appropriate interface */
143*0a6a1f1dSLionel Sambuc #endif
144*0a6a1f1dSLionel Sambuc 		m6.ipv6mr_interface = ifc;
145*0a6a1f1dSLionel Sambuc 		m6.ipv6mr_multiaddr = s6->sin6_addr;
146*0a6a1f1dSLionel Sambuc 		return setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP,
147*0a6a1f1dSLionel Sambuc 		    &m6, sizeof(m6));
148*0a6a1f1dSLionel Sambuc 	default:
149*0a6a1f1dSLionel Sambuc 		errno = EOPNOTSUPP;
150*0a6a1f1dSLionel Sambuc 		return -1;
151*0a6a1f1dSLionel Sambuc 	}
152*0a6a1f1dSLionel Sambuc }
153*0a6a1f1dSLionel Sambuc 
154*0a6a1f1dSLionel Sambuc static int
allowv4mapped(int s,struct addrinfo * ai)155*0a6a1f1dSLionel Sambuc allowv4mapped(int s, struct addrinfo *ai)
156*0a6a1f1dSLionel Sambuc {
157*0a6a1f1dSLionel Sambuc 	struct sockaddr_in6 *s6;
158*0a6a1f1dSLionel Sambuc 	int zero = 0;
159*0a6a1f1dSLionel Sambuc 
160*0a6a1f1dSLionel Sambuc 	if (ai->ai_family != AF_INET6)
161*0a6a1f1dSLionel Sambuc 		return 0;
162*0a6a1f1dSLionel Sambuc 
163*0a6a1f1dSLionel Sambuc 	s6 = (void *)ai->ai_addr;
164*0a6a1f1dSLionel Sambuc 
165*0a6a1f1dSLionel Sambuc 	if (!IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr))
166*0a6a1f1dSLionel Sambuc 		return 0;
167*0a6a1f1dSLionel Sambuc 	return setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
168*0a6a1f1dSLionel Sambuc }
169*0a6a1f1dSLionel Sambuc 
170*0a6a1f1dSLionel Sambuc static struct sockaddr_storage ss;
171*0a6a1f1dSLionel Sambuc static int
connector(int fd,const struct sockaddr * sa,socklen_t slen)172*0a6a1f1dSLionel Sambuc connector(int fd, const struct sockaddr *sa, socklen_t slen)
173*0a6a1f1dSLionel Sambuc {
174*0a6a1f1dSLionel Sambuc 	assert(sizeof(ss) > slen);
175*0a6a1f1dSLionel Sambuc 	memcpy(&ss, sa, slen);
176*0a6a1f1dSLionel Sambuc 	return 0;
177*0a6a1f1dSLionel Sambuc }
178*0a6a1f1dSLionel Sambuc 
179*0a6a1f1dSLionel Sambuc static void
show(const char * prefix,const struct message * msg)180*0a6a1f1dSLionel Sambuc show(const char *prefix, const struct message *msg)
181*0a6a1f1dSLionel Sambuc {
182*0a6a1f1dSLionel Sambuc 	printf("%10.10s: %zu [%jd.%ld]\n", prefix, msg->seq, (intmax_t)
183*0a6a1f1dSLionel Sambuc 	    msg->ts.tv_sec, msg->ts.tv_nsec);
184*0a6a1f1dSLionel Sambuc }
185*0a6a1f1dSLionel Sambuc 
186*0a6a1f1dSLionel Sambuc static int
getsocket(const char * host,const char * port,int (* f)(int,const struct sockaddr *,socklen_t),socklen_t * slen,bool bug)187*0a6a1f1dSLionel Sambuc getsocket(const char *host, const char *port,
188*0a6a1f1dSLionel Sambuc     int (*f)(int, const struct sockaddr *, socklen_t), socklen_t *slen,
189*0a6a1f1dSLionel Sambuc     bool bug)
190*0a6a1f1dSLionel Sambuc {
191*0a6a1f1dSLionel Sambuc 	int e, s, lasterrno = 0;
192*0a6a1f1dSLionel Sambuc 	struct addrinfo hints, *ai0, *ai;
193*0a6a1f1dSLionel Sambuc 	const char *cause = "?";
194*0a6a1f1dSLionel Sambuc 
195*0a6a1f1dSLionel Sambuc 	memset(&hints, 0, sizeof(hints));
196*0a6a1f1dSLionel Sambuc 	hints.ai_family = AF_UNSPEC;
197*0a6a1f1dSLionel Sambuc 	hints.ai_socktype = SOCK_DGRAM;
198*0a6a1f1dSLionel Sambuc 	e = getaddrinfo(host, port, &hints, &ai0);
199*0a6a1f1dSLionel Sambuc 	if (e)
200*0a6a1f1dSLionel Sambuc 		ERRX(EXIT_FAILURE, "Can't resolve %s:%s (%s)", host, port,
201*0a6a1f1dSLionel Sambuc 		    gai_strerror(e));
202*0a6a1f1dSLionel Sambuc 
203*0a6a1f1dSLionel Sambuc 	s = -1;
204*0a6a1f1dSLionel Sambuc 	for (ai = ai0; ai; ai = ai->ai_next) {
205*0a6a1f1dSLionel Sambuc 		s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
206*0a6a1f1dSLionel Sambuc 		if (s == -1) {
207*0a6a1f1dSLionel Sambuc 			lasterrno = errno;
208*0a6a1f1dSLionel Sambuc 			cause = "socket";
209*0a6a1f1dSLionel Sambuc 			continue;
210*0a6a1f1dSLionel Sambuc 		}
211*0a6a1f1dSLionel Sambuc 		if (allowv4mapped(s, ai) == -1) {
212*0a6a1f1dSLionel Sambuc 			cause = "allow v4 mapped";
213*0a6a1f1dSLionel Sambuc 			goto out;
214*0a6a1f1dSLionel Sambuc 		}
215*0a6a1f1dSLionel Sambuc 		if ((*f)(s, ai->ai_addr, ai->ai_addrlen) == -1) {
216*0a6a1f1dSLionel Sambuc 			cause = f == bind ? "bind" : "connect";
217*0a6a1f1dSLionel Sambuc 			goto out;
218*0a6a1f1dSLionel Sambuc 		}
219*0a6a1f1dSLionel Sambuc 		if ((f == bind || f == connector) && addmc(s, ai, bug) == -1) {
220*0a6a1f1dSLionel Sambuc 			cause = "join group";
221*0a6a1f1dSLionel Sambuc 			goto out;
222*0a6a1f1dSLionel Sambuc 		}
223*0a6a1f1dSLionel Sambuc 		*slen = ai->ai_addrlen;
224*0a6a1f1dSLionel Sambuc 		break;
225*0a6a1f1dSLionel Sambuc out:
226*0a6a1f1dSLionel Sambuc 		lasterrno = errno;
227*0a6a1f1dSLionel Sambuc 		close(s);
228*0a6a1f1dSLionel Sambuc 		s = -1;
229*0a6a1f1dSLionel Sambuc 		continue;
230*0a6a1f1dSLionel Sambuc 	}
231*0a6a1f1dSLionel Sambuc 	freeaddrinfo(ai0);
232*0a6a1f1dSLionel Sambuc 	if (s == -1)
233*0a6a1f1dSLionel Sambuc 		ERRX(EXIT_FAILURE, "%s (%s)", cause, strerror(lasterrno));
234*0a6a1f1dSLionel Sambuc 	return s;
235*0a6a1f1dSLionel Sambuc }
236*0a6a1f1dSLionel Sambuc 
237*0a6a1f1dSLionel Sambuc static int
synchronize(const int fd,bool waiter)238*0a6a1f1dSLionel Sambuc synchronize(const int fd, bool waiter)
239*0a6a1f1dSLionel Sambuc {
240*0a6a1f1dSLionel Sambuc 	int syncmsg = 0;
241*0a6a1f1dSLionel Sambuc 	int r;
242*0a6a1f1dSLionel Sambuc 	struct pollfd pfd;
243*0a6a1f1dSLionel Sambuc 
244*0a6a1f1dSLionel Sambuc 	if (waiter) {
245*0a6a1f1dSLionel Sambuc 		pfd.fd = fd;
246*0a6a1f1dSLionel Sambuc 		pfd.events = POLLIN;
247*0a6a1f1dSLionel Sambuc 
248*0a6a1f1dSLionel Sambuc 		/* We use poll to avoid lock up when the peer died unexpectedly */
249*0a6a1f1dSLionel Sambuc 		r = poll(&pfd, 1, 10000);
250*0a6a1f1dSLionel Sambuc 		if (r == -1)
251*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "poll (%s)", strerror(errno));
252*0a6a1f1dSLionel Sambuc 		if (r == 0)
253*0a6a1f1dSLionel Sambuc 			/* Timed out */
254*0a6a1f1dSLionel Sambuc 			return -1;
255*0a6a1f1dSLionel Sambuc 
256*0a6a1f1dSLionel Sambuc 		if (read(fd, &syncmsg, sizeof(syncmsg)) == -1)
257*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "read (%s)", strerror(errno));
258*0a6a1f1dSLionel Sambuc 	} else {
259*0a6a1f1dSLionel Sambuc 		if (write(fd, &syncmsg, sizeof(syncmsg)) == -1)
260*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "write (%s)", strerror(errno));
261*0a6a1f1dSLionel Sambuc 	}
262*0a6a1f1dSLionel Sambuc 
263*0a6a1f1dSLionel Sambuc 	return 0;
264*0a6a1f1dSLionel Sambuc }
265*0a6a1f1dSLionel Sambuc 
266*0a6a1f1dSLionel Sambuc static int
sender(const int fd,const char * host,const char * port,size_t n,bool conn,bool bug)267*0a6a1f1dSLionel Sambuc sender(const int fd, const char *host, const char *port, size_t n, bool conn,
268*0a6a1f1dSLionel Sambuc     bool bug)
269*0a6a1f1dSLionel Sambuc {
270*0a6a1f1dSLionel Sambuc 	int s;
271*0a6a1f1dSLionel Sambuc 	ssize_t l;
272*0a6a1f1dSLionel Sambuc 	struct message msg;
273*0a6a1f1dSLionel Sambuc 
274*0a6a1f1dSLionel Sambuc 	socklen_t slen;
275*0a6a1f1dSLionel Sambuc 
276*0a6a1f1dSLionel Sambuc 	s = getsocket(host, port, conn ? connect : connector, &slen, bug);
277*0a6a1f1dSLionel Sambuc 
278*0a6a1f1dSLionel Sambuc 	/* Wait until receiver gets ready. */
279*0a6a1f1dSLionel Sambuc 	if (synchronize(fd, true) == -1)
280*0a6a1f1dSLionel Sambuc 		return -1;
281*0a6a1f1dSLionel Sambuc 
282*0a6a1f1dSLionel Sambuc 	for (msg.seq = 0; msg.seq < n; msg.seq++) {
283*0a6a1f1dSLionel Sambuc #ifdef CLOCK_MONOTONIC
284*0a6a1f1dSLionel Sambuc 		if (clock_gettime(CLOCK_MONOTONIC, &msg.ts) == -1)
285*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "clock (%s)", strerror(errno));
286*0a6a1f1dSLionel Sambuc #else
287*0a6a1f1dSLionel Sambuc 		struct timeval tv;
288*0a6a1f1dSLionel Sambuc 		if (gettimeofday(&tv, NULL) == -1)
289*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "clock (%s)", strerror(errno));
290*0a6a1f1dSLionel Sambuc 		msg.ts.tv_sec = tv.tv_sec;
291*0a6a1f1dSLionel Sambuc 		msg.ts.tv_nsec = tv.tv_usec * 1000;
292*0a6a1f1dSLionel Sambuc #endif
293*0a6a1f1dSLionel Sambuc 		if (debug)
294*0a6a1f1dSLionel Sambuc 			show("sending", &msg);
295*0a6a1f1dSLionel Sambuc 		l = conn ? send(s, &msg, sizeof(msg), 0) :
296*0a6a1f1dSLionel Sambuc 		    sendto(s, &msg, sizeof(msg), 0, (void *)&ss, slen);
297*0a6a1f1dSLionel Sambuc 		if (l == -1)
298*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "send (%s)", strerror(errno));
299*0a6a1f1dSLionel Sambuc 		usleep(100);
300*0a6a1f1dSLionel Sambuc 	}
301*0a6a1f1dSLionel Sambuc 
302*0a6a1f1dSLionel Sambuc 	/* Wait until receiver finishes its work. */
303*0a6a1f1dSLionel Sambuc 	if (synchronize(fd, true) == -1)
304*0a6a1f1dSLionel Sambuc 		return -1;
305*0a6a1f1dSLionel Sambuc 
306*0a6a1f1dSLionel Sambuc 	return 0;
307*0a6a1f1dSLionel Sambuc }
308*0a6a1f1dSLionel Sambuc 
309*0a6a1f1dSLionel Sambuc static void
receiver(const int fd,const char * host,const char * port,size_t n,bool conn,bool bug)310*0a6a1f1dSLionel Sambuc receiver(const int fd, const char *host, const char *port, size_t n, bool conn,
311*0a6a1f1dSLionel Sambuc     bool bug)
312*0a6a1f1dSLionel Sambuc {
313*0a6a1f1dSLionel Sambuc 	int s;
314*0a6a1f1dSLionel Sambuc 	ssize_t l;
315*0a6a1f1dSLionel Sambuc 	size_t seq;
316*0a6a1f1dSLionel Sambuc 	struct message msg;
317*0a6a1f1dSLionel Sambuc 	struct pollfd pfd;
318*0a6a1f1dSLionel Sambuc 	socklen_t slen;
319*0a6a1f1dSLionel Sambuc 
320*0a6a1f1dSLionel Sambuc 	s = getsocket(host, port, bind, &slen, bug);
321*0a6a1f1dSLionel Sambuc 	pfd.fd = s;
322*0a6a1f1dSLionel Sambuc 	pfd.events = POLLIN;
323*0a6a1f1dSLionel Sambuc 
324*0a6a1f1dSLionel Sambuc 	/* Tell I'm ready */
325*0a6a1f1dSLionel Sambuc 	synchronize(fd, false);
326*0a6a1f1dSLionel Sambuc 
327*0a6a1f1dSLionel Sambuc 	for (seq = 0; seq < n; seq++) {
328*0a6a1f1dSLionel Sambuc 		if (poll(&pfd, 1, 10000) == -1)
329*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "poll (%s)", strerror(errno));
330*0a6a1f1dSLionel Sambuc 		l = conn ? recv(s, &msg, sizeof(msg), 0) :
331*0a6a1f1dSLionel Sambuc 		    recvfrom(s, &msg, sizeof(msg), 0, (void *)&ss, &slen);
332*0a6a1f1dSLionel Sambuc 		if (l == -1)
333*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "recv (%s)", strerror(errno));
334*0a6a1f1dSLionel Sambuc 		if (debug)
335*0a6a1f1dSLionel Sambuc 			show("got", &msg);
336*0a6a1f1dSLionel Sambuc 		if (seq != msg.seq)
337*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "seq: expect=%zu actual=%zu",
338*0a6a1f1dSLionel Sambuc 			    seq, msg.seq);
339*0a6a1f1dSLionel Sambuc 	}
340*0a6a1f1dSLionel Sambuc 
341*0a6a1f1dSLionel Sambuc 	/* Tell I'm finished */
342*0a6a1f1dSLionel Sambuc 	synchronize(fd, false);
343*0a6a1f1dSLionel Sambuc }
344*0a6a1f1dSLionel Sambuc 
345*0a6a1f1dSLionel Sambuc static void
run(const char * host,const char * port,size_t n,bool conn,bool bug)346*0a6a1f1dSLionel Sambuc run(const char *host, const char *port, size_t n, bool conn, bool bug)
347*0a6a1f1dSLionel Sambuc {
348*0a6a1f1dSLionel Sambuc 	pid_t pid;
349*0a6a1f1dSLionel Sambuc 	int status;
350*0a6a1f1dSLionel Sambuc 	int syncfds[2];
351*0a6a1f1dSLionel Sambuc 	int error;
352*0a6a1f1dSLionel Sambuc 
353*0a6a1f1dSLionel Sambuc 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, syncfds) == -1)
354*0a6a1f1dSLionel Sambuc 		ERRX(EXIT_FAILURE, "socketpair (%s)", strerror(errno));
355*0a6a1f1dSLionel Sambuc 
356*0a6a1f1dSLionel Sambuc 	switch ((pid = fork())) {
357*0a6a1f1dSLionel Sambuc 	case 0:
358*0a6a1f1dSLionel Sambuc 		receiver(syncfds[0], host, port, n, conn, bug);
359*0a6a1f1dSLionel Sambuc 		return;
360*0a6a1f1dSLionel Sambuc 	case -1:
361*0a6a1f1dSLionel Sambuc 		ERRX(EXIT_FAILURE, "fork (%s)", strerror(errno));
362*0a6a1f1dSLionel Sambuc 	default:
363*0a6a1f1dSLionel Sambuc 		error = sender(syncfds[1], host, port, n, conn, bug);
364*0a6a1f1dSLionel Sambuc 	again:
365*0a6a1f1dSLionel Sambuc 		switch (waitpid(pid, &status, WNOHANG)) {
366*0a6a1f1dSLionel Sambuc 		case -1:
367*0a6a1f1dSLionel Sambuc 			ERRX(EXIT_FAILURE, "wait (%s)", strerror(errno));
368*0a6a1f1dSLionel Sambuc 		case 0:
369*0a6a1f1dSLionel Sambuc 			if (error == 0)
370*0a6a1f1dSLionel Sambuc 				/*
371*0a6a1f1dSLionel Sambuc 				 * Receiver is still alive, but we know
372*0a6a1f1dSLionel Sambuc 				 * it will exit soon.
373*0a6a1f1dSLionel Sambuc 				 */
374*0a6a1f1dSLionel Sambuc 				goto again;
375*0a6a1f1dSLionel Sambuc 
376*0a6a1f1dSLionel Sambuc 			if (kill(pid, SIGTERM) == -1)
377*0a6a1f1dSLionel Sambuc 				ERRX(EXIT_FAILURE, "kill (%s)",
378*0a6a1f1dSLionel Sambuc 				    strerror(errno));
379*0a6a1f1dSLionel Sambuc 			goto again;
380*0a6a1f1dSLionel Sambuc 		default:
381*0a6a1f1dSLionel Sambuc 			if (WIFSIGNALED(status)) {
382*0a6a1f1dSLionel Sambuc 				if (WTERMSIG(status) == SIGTERM)
383*0a6a1f1dSLionel Sambuc 					ERRX0(EXIT_FAILURE,
384*0a6a1f1dSLionel Sambuc 					    "receiver failed and was killed" \
385*0a6a1f1dSLionel Sambuc 					    "by sender");
386*0a6a1f1dSLionel Sambuc 				else
387*0a6a1f1dSLionel Sambuc 					ERRX(EXIT_FAILURE,
388*0a6a1f1dSLionel Sambuc 					    "receiver got signaled (%s)",
389*0a6a1f1dSLionel Sambuc 					    strsignal(WTERMSIG(status)));
390*0a6a1f1dSLionel Sambuc 			} else if (WIFEXITED(status)) {
391*0a6a1f1dSLionel Sambuc 				if (WEXITSTATUS(status) != 0)
392*0a6a1f1dSLionel Sambuc 					ERRX(EXIT_FAILURE,
393*0a6a1f1dSLionel Sambuc 					    "receiver exited with status %d",
394*0a6a1f1dSLionel Sambuc 					    WEXITSTATUS(status));
395*0a6a1f1dSLionel Sambuc 			} else {
396*0a6a1f1dSLionel Sambuc 				ERRX(EXIT_FAILURE,
397*0a6a1f1dSLionel Sambuc 				    "receiver exited with unexpected status %d",
398*0a6a1f1dSLionel Sambuc 				    status);
399*0a6a1f1dSLionel Sambuc 			}
400*0a6a1f1dSLionel Sambuc 			break;
401*0a6a1f1dSLionel Sambuc 		}
402*0a6a1f1dSLionel Sambuc 		return;
403*0a6a1f1dSLionel Sambuc 	}
404*0a6a1f1dSLionel Sambuc }
405*0a6a1f1dSLionel Sambuc 
406*0a6a1f1dSLionel Sambuc #ifndef ATF
407*0a6a1f1dSLionel Sambuc int
main(int argc,char * argv[])408*0a6a1f1dSLionel Sambuc main(int argc, char *argv[])
409*0a6a1f1dSLionel Sambuc {
410*0a6a1f1dSLionel Sambuc 	const char *host, *port;
411*0a6a1f1dSLionel Sambuc 	int c;
412*0a6a1f1dSLionel Sambuc 	size_t n;
413*0a6a1f1dSLionel Sambuc 	bool conn, bug;
414*0a6a1f1dSLionel Sambuc 
415*0a6a1f1dSLionel Sambuc 	host = HOST_V4;
416*0a6a1f1dSLionel Sambuc 	port = PORT_V4;
417*0a6a1f1dSLionel Sambuc 	n = TOTAL;
418*0a6a1f1dSLionel Sambuc 	bug = conn = false;
419*0a6a1f1dSLionel Sambuc 
420*0a6a1f1dSLionel Sambuc 	while ((c = getopt(argc, argv, "46bcdmn:")) != -1)
421*0a6a1f1dSLionel Sambuc 		switch (c) {
422*0a6a1f1dSLionel Sambuc 		case '4':
423*0a6a1f1dSLionel Sambuc 			host = HOST_V4;
424*0a6a1f1dSLionel Sambuc 			port = PORT_V4;
425*0a6a1f1dSLionel Sambuc 			break;
426*0a6a1f1dSLionel Sambuc 		case '6':
427*0a6a1f1dSLionel Sambuc 			host = HOST_V6;
428*0a6a1f1dSLionel Sambuc 			port = PORT_V6;
429*0a6a1f1dSLionel Sambuc 			break;
430*0a6a1f1dSLionel Sambuc 		case 'b':
431*0a6a1f1dSLionel Sambuc 			bug = true;
432*0a6a1f1dSLionel Sambuc 			break;
433*0a6a1f1dSLionel Sambuc 		case 'c':
434*0a6a1f1dSLionel Sambuc 			conn = true;
435*0a6a1f1dSLionel Sambuc 			break;
436*0a6a1f1dSLionel Sambuc 		case 'd':
437*0a6a1f1dSLionel Sambuc 			debug++;
438*0a6a1f1dSLionel Sambuc 			break;
439*0a6a1f1dSLionel Sambuc 		case 'm':
440*0a6a1f1dSLionel Sambuc 			host = HOST_V4MAPPED;
441*0a6a1f1dSLionel Sambuc 			port = PORT_V4MAPPED;
442*0a6a1f1dSLionel Sambuc 			break;
443*0a6a1f1dSLionel Sambuc 		case 'n':
444*0a6a1f1dSLionel Sambuc 			n = atoi(optarg);
445*0a6a1f1dSLionel Sambuc 			break;
446*0a6a1f1dSLionel Sambuc 		default:
447*0a6a1f1dSLionel Sambuc 			fprintf(stderr, "Usage: %s [-cdm46] [-n <tot>]",
448*0a6a1f1dSLionel Sambuc 			    getprogname());
449*0a6a1f1dSLionel Sambuc 			return 1;
450*0a6a1f1dSLionel Sambuc 		}
451*0a6a1f1dSLionel Sambuc 
452*0a6a1f1dSLionel Sambuc 	run(host, port, n, conn, bug);
453*0a6a1f1dSLionel Sambuc 	return 0;
454*0a6a1f1dSLionel Sambuc }
455*0a6a1f1dSLionel Sambuc #else
456*0a6a1f1dSLionel Sambuc 
457*0a6a1f1dSLionel Sambuc ATF_TC(conninet4);
ATF_TC_HEAD(conninet4,tc)458*0a6a1f1dSLionel Sambuc ATF_TC_HEAD(conninet4, tc)
459*0a6a1f1dSLionel Sambuc {
460*0a6a1f1dSLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks connected multicast for ipv4");
461*0a6a1f1dSLionel Sambuc }
462*0a6a1f1dSLionel Sambuc 
ATF_TC_BODY(conninet4,tc)463*0a6a1f1dSLionel Sambuc ATF_TC_BODY(conninet4, tc)
464*0a6a1f1dSLionel Sambuc {
465*0a6a1f1dSLionel Sambuc 	run(HOST_V4, PORT_V4, TOTAL, true, false);
466*0a6a1f1dSLionel Sambuc }
467*0a6a1f1dSLionel Sambuc 
468*0a6a1f1dSLionel Sambuc ATF_TC(connmappedinet4);
ATF_TC_HEAD(connmappedinet4,tc)469*0a6a1f1dSLionel Sambuc ATF_TC_HEAD(connmappedinet4, tc)
470*0a6a1f1dSLionel Sambuc {
471*0a6a1f1dSLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks connected multicast for mapped ipv4");
472*0a6a1f1dSLionel Sambuc }
473*0a6a1f1dSLionel Sambuc 
ATF_TC_BODY(connmappedinet4,tc)474*0a6a1f1dSLionel Sambuc ATF_TC_BODY(connmappedinet4, tc)
475*0a6a1f1dSLionel Sambuc {
476*0a6a1f1dSLionel Sambuc 	run(HOST_V4MAPPED, PORT_V4MAPPED, TOTAL, true, false);
477*0a6a1f1dSLionel Sambuc }
478*0a6a1f1dSLionel Sambuc 
479*0a6a1f1dSLionel Sambuc ATF_TC(connmappedbuginet4);
ATF_TC_HEAD(connmappedbuginet4,tc)480*0a6a1f1dSLionel Sambuc ATF_TC_HEAD(connmappedbuginet4, tc)
481*0a6a1f1dSLionel Sambuc {
482*0a6a1f1dSLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks connected multicast for mapped ipv4 using the v4 ioctls");
483*0a6a1f1dSLionel Sambuc }
484*0a6a1f1dSLionel Sambuc 
ATF_TC_BODY(connmappedbuginet4,tc)485*0a6a1f1dSLionel Sambuc ATF_TC_BODY(connmappedbuginet4, tc)
486*0a6a1f1dSLionel Sambuc {
487*0a6a1f1dSLionel Sambuc 	run(HOST_V4MAPPED, PORT_V4MAPPED, TOTAL, true, true);
488*0a6a1f1dSLionel Sambuc }
489*0a6a1f1dSLionel Sambuc 
490*0a6a1f1dSLionel Sambuc ATF_TC(conninet6);
ATF_TC_HEAD(conninet6,tc)491*0a6a1f1dSLionel Sambuc ATF_TC_HEAD(conninet6, tc)
492*0a6a1f1dSLionel Sambuc {
493*0a6a1f1dSLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks connected multicast for ipv6");
494*0a6a1f1dSLionel Sambuc }
495*0a6a1f1dSLionel Sambuc 
ATF_TC_BODY(conninet6,tc)496*0a6a1f1dSLionel Sambuc ATF_TC_BODY(conninet6, tc)
497*0a6a1f1dSLionel Sambuc {
498*0a6a1f1dSLionel Sambuc 	run(HOST_V6, PORT_V6, TOTAL, true, false);
499*0a6a1f1dSLionel Sambuc }
500*0a6a1f1dSLionel Sambuc 
501*0a6a1f1dSLionel Sambuc ATF_TC(unconninet4);
ATF_TC_HEAD(unconninet4,tc)502*0a6a1f1dSLionel Sambuc ATF_TC_HEAD(unconninet4, tc)
503*0a6a1f1dSLionel Sambuc {
504*0a6a1f1dSLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks unconnected multicast for ipv4");
505*0a6a1f1dSLionel Sambuc }
506*0a6a1f1dSLionel Sambuc 
ATF_TC_BODY(unconninet4,tc)507*0a6a1f1dSLionel Sambuc ATF_TC_BODY(unconninet4, tc)
508*0a6a1f1dSLionel Sambuc {
509*0a6a1f1dSLionel Sambuc 	run(HOST_V4, PORT_V4, TOTAL, false, false);
510*0a6a1f1dSLionel Sambuc }
511*0a6a1f1dSLionel Sambuc 
512*0a6a1f1dSLionel Sambuc ATF_TC(unconnmappedinet4);
ATF_TC_HEAD(unconnmappedinet4,tc)513*0a6a1f1dSLionel Sambuc ATF_TC_HEAD(unconnmappedinet4, tc)
514*0a6a1f1dSLionel Sambuc {
515*0a6a1f1dSLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks unconnected multicast for mapped ipv4");
516*0a6a1f1dSLionel Sambuc }
517*0a6a1f1dSLionel Sambuc 
ATF_TC_BODY(unconnmappedinet4,tc)518*0a6a1f1dSLionel Sambuc ATF_TC_BODY(unconnmappedinet4, tc)
519*0a6a1f1dSLionel Sambuc {
520*0a6a1f1dSLionel Sambuc 	run(HOST_V4MAPPED, PORT_V4MAPPED, TOTAL, false, false);
521*0a6a1f1dSLionel Sambuc }
522*0a6a1f1dSLionel Sambuc 
523*0a6a1f1dSLionel Sambuc ATF_TC(unconnmappedbuginet4);
ATF_TC_HEAD(unconnmappedbuginet4,tc)524*0a6a1f1dSLionel Sambuc ATF_TC_HEAD(unconnmappedbuginet4, tc)
525*0a6a1f1dSLionel Sambuc {
526*0a6a1f1dSLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks unconnected multicast for mapped ipv4 using the v4 ioctls");
527*0a6a1f1dSLionel Sambuc }
528*0a6a1f1dSLionel Sambuc 
ATF_TC_BODY(unconnmappedbuginet4,tc)529*0a6a1f1dSLionel Sambuc ATF_TC_BODY(unconnmappedbuginet4, tc)
530*0a6a1f1dSLionel Sambuc {
531*0a6a1f1dSLionel Sambuc 	run(HOST_V4MAPPED, PORT_V4MAPPED, TOTAL, false, true);
532*0a6a1f1dSLionel Sambuc }
533*0a6a1f1dSLionel Sambuc 
534*0a6a1f1dSLionel Sambuc ATF_TC(unconninet6);
ATF_TC_HEAD(unconninet6,tc)535*0a6a1f1dSLionel Sambuc ATF_TC_HEAD(unconninet6, tc)
536*0a6a1f1dSLionel Sambuc {
537*0a6a1f1dSLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks unconnected multicast for ipv6");
538*0a6a1f1dSLionel Sambuc }
539*0a6a1f1dSLionel Sambuc 
ATF_TC_BODY(unconninet6,tc)540*0a6a1f1dSLionel Sambuc ATF_TC_BODY(unconninet6, tc)
541*0a6a1f1dSLionel Sambuc {
542*0a6a1f1dSLionel Sambuc 	run(HOST_V6, PORT_V6, TOTAL, false, false);
543*0a6a1f1dSLionel Sambuc }
544*0a6a1f1dSLionel Sambuc 
ATF_TP_ADD_TCS(tp)545*0a6a1f1dSLionel Sambuc ATF_TP_ADD_TCS(tp)
546*0a6a1f1dSLionel Sambuc {
547*0a6a1f1dSLionel Sambuc 	debug++;
548*0a6a1f1dSLionel Sambuc 	ATF_TP_ADD_TC(tp, conninet4);
549*0a6a1f1dSLionel Sambuc 	ATF_TP_ADD_TC(tp, connmappedinet4);
550*0a6a1f1dSLionel Sambuc 	ATF_TP_ADD_TC(tp, connmappedbuginet4);
551*0a6a1f1dSLionel Sambuc 	ATF_TP_ADD_TC(tp, conninet6);
552*0a6a1f1dSLionel Sambuc 	ATF_TP_ADD_TC(tp, unconninet4);
553*0a6a1f1dSLionel Sambuc 	ATF_TP_ADD_TC(tp, unconnmappedinet4);
554*0a6a1f1dSLionel Sambuc 	ATF_TP_ADD_TC(tp, unconnmappedbuginet4);
555*0a6a1f1dSLionel Sambuc 	ATF_TP_ADD_TC(tp, unconninet6);
556*0a6a1f1dSLionel Sambuc 
557*0a6a1f1dSLionel Sambuc 	return atf_no_error();
558*0a6a1f1dSLionel Sambuc }
559*0a6a1f1dSLionel Sambuc #endif
560