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