Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/tests/net add a multicast test (what to do with v6?)
details: https://anonhg.NetBSD.org/src/rev/5bce10865eaa
branches: trunk
changeset: 332918:5bce10865eaa
user: christos <christos%NetBSD.org@localhost>
date: Sat Oct 11 23:04:42 2014 +0000
description:
add a multicast test (what to do with v6?)
diffstat:
tests/net/Makefile | 4 +-
tests/net/mcast/Makefile | 10 +
tests/net/mcast/t_mcast.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 331 insertions(+), 2 deletions(-)
diffs (truncated from 353 to 300 lines):
diff -r ff36f989c78d -r 5bce10865eaa tests/net/Makefile
--- a/tests/net/Makefile Sat Oct 11 21:28:43 2014 +0000
+++ b/tests/net/Makefile Sat Oct 11 23:04:42 2014 +0000
@@ -1,10 +1,10 @@
-# $NetBSD: Makefile,v 1.18 2014/09/18 15:13:27 ozaki-r Exp $
+# $NetBSD: Makefile,v 1.19 2014/10/11 23:04:42 christos Exp $
.include <bsd.own.mk>
TESTSDIR= ${TESTSBASE}/net
-TESTS_SUBDIRS= fdpass net route sys
+TESTS_SUBDIRS= fdpass mcast net route sys
.if (${MKRUMP} != "no")
TESTS_SUBDIRS+= bpf bpfilter carp icmp if if_bridge if_loop mpls npf
.if (${MKSLJIT} != "no")
diff -r ff36f989c78d -r 5bce10865eaa tests/net/mcast/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/net/mcast/Makefile Sat Oct 11 23:04:42 2014 +0000
@@ -0,0 +1,10 @@
+# $NetBSD: Makefile,v 1.1 2014/10/11 23:04:42 christos Exp $
+#
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/net/mcast
+
+TESTS_C= t_mcast
+
+.include <bsd.test.mk>
diff -r ff36f989c78d -r 5bce10865eaa tests/net/mcast/t_mcast.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/net/mcast/t_mcast.c Sat Oct 11 23:04:42 2014 +0000
@@ -0,0 +1,319 @@
+/* $NetBSD: t_mcast.c,v 1.1 2014/10/11 23:04:42 christos Exp $ */
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_mcast.c,v 1.1 2014/10/11 23:04:42 christos Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <netdb.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+#include <poll.h>
+
+#ifndef TEST
+#include <atf-c.h>
+
+#define ERRX(ev, msg, ...) ATF_REQUIRE_MSG(0, msg, __VA_ARGS__)
+
+#define SKIPX(ev, msg, ...) do { \
+ atf_tc_skip(msg, __VA_ARGS__); \
+ return; \
+} while(/*CONSTCOND*/0)
+
+#else
+#define ERRX(ev, msg, ...) errx(ev, msg, __VA_ARGS__)
+#define SKIPX(ev, msg, ...) errx(ev, msg, __VA_ARGS__)
+#endif
+
+static int debug;
+
+#define TOTAL 10
+#define PORT_V4MAPPED "6666"
+#define HOST_V4MAPPED "::FFFF:239.1.1.1"
+#define PORT_V4 "6666"
+#define HOST_V4 "239.1.1.1"
+#define PORT_V6 "6666"
+#define HOST_V6 "FF05:0:0:0:0:0:0:1"
+
+static int
+addmc(int s, struct addrinfo *ai)
+{
+ struct ip_mreq m4;
+ struct ipv6_mreq m6;
+ struct sockaddr_in *s4;
+ struct sockaddr_in6 *s6;
+
+ switch (ai->ai_family) {
+ case AF_INET:
+ s4 = (void *)ai->ai_addr;
+ assert(sizeof(*s4) == ai->ai_addrlen);
+ m4.imr_multiaddr = s4->sin_addr;
+ m4.imr_interface.s_addr = htonl(INADDR_ANY);
+ return setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &m4, sizeof(m4));
+ case AF_INET6:
+ s6 = (void *)ai->ai_addr;
+ // XXX: Both linux and we do this thing wrong...
+ if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) {
+ memcpy(&m4.imr_multiaddr, &s6->sin6_addr.s6_addr[12],
+ sizeof(m4.imr_multiaddr));
+ m4.imr_interface.s_addr = htonl(INADDR_ANY);
+ return setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &m4, sizeof(m4));
+ }
+ assert(sizeof(*s6) == ai->ai_addrlen);
+ memset(&m6, 0, sizeof(m6));
+ m6.ipv6mr_interface = 0;
+ m6.ipv6mr_multiaddr = s6->sin6_addr;
+ return setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &m6, sizeof(m6));
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+}
+
+static int
+allowv4mapped(int s, struct addrinfo *ai)
+{
+ struct sockaddr_in6 *s6;
+ int zero = 0;
+
+ if (ai->ai_family != AF_INET6)
+ return 0;
+
+ s6 = (void *)ai->ai_addr;
+
+ if (!IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr))
+ return 0;
+ return setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
+}
+
+static int
+getsocket(const char *host, const char *port,
+ int (*f)(int, const struct sockaddr *, socklen_t))
+{
+ int e, s;
+ struct addrinfo hints, *ai0, *ai;
+ const char *cause = "?";
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ e = getaddrinfo(host, port, &hints, &ai0);
+ if (e)
+ ERRX(EXIT_FAILURE, "Can't resolve %s:%s (%s)", host, port,
+ gai_strerror(e));
+
+ s = -1;
+ for (ai = ai0; ai; ai = ai->ai_next) {
+ s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (s == -1) {
+ cause = "socket";
+ continue;
+ }
+ if (allowv4mapped(s, ai) == -1) {
+ cause = "allow v4 mapped";
+ goto out;
+ }
+ if ((*f)(s, ai->ai_addr, ai->ai_addrlen) == -1) {
+ cause = f == bind ? "bind" : "connect";
+ goto out;
+ }
+ if (f == bind && addmc(s, ai) == -1) {
+ cause = "join group";
+ goto out;
+ }
+ break;
+out:
+ close(s);
+ s = -1;
+ continue;
+ }
+ freeaddrinfo(ai0);
+ if (s == -1)
+ ERRX(1, "%s (%s)", cause, strerror(errno));
+ return s;
+}
+
+static void
+sender(const char *host, const char *port, size_t n)
+{
+ int s;
+ ssize_t l;
+ size_t seq;
+ char buf[64];
+
+ s = getsocket(host, port, connect);
+ for (seq = 0; seq < n; seq++) {
+ time_t t = time(&t);
+ snprintf(buf, sizeof(buf), "%zu: %-24.24s", seq, ctime(&t));
+ if (debug)
+ printf("sending: %s\n", buf);
+ l = send(s, buf, sizeof(buf), 0);
+ if (l == -1)
+ ERRX(EXIT_FAILURE, "send (%s)", strerror(errno));
+ usleep(100);
+ }
+}
+
+static void
+receiver(const char *host, const char *port, size_t n)
+{
+ int s;
+ ssize_t l;
+ size_t seq;
+ char buf[64];
+ struct pollfd pfd;
+
+ s = getsocket(host, port, bind);
+ pfd.fd = s;
+ pfd.events = POLLIN;
+ for (seq = 0; seq < n; seq++) {
+ if (poll(&pfd, 1, 1000) == -1)
+ ERRX(EXIT_FAILURE, "poll (%s)", strerror(errno));
+ l = recv(s, buf, sizeof(buf), 0);
+ if (l == -1)
+ ERRX(EXIT_FAILURE, "recv (%s)", strerror(errno));
+ if (debug)
+ printf("got: %s\n", buf);
+ }
+}
+
+static void
+run(const char *host, const char *port, size_t n)
+{
+ switch (fork()) {
+ case 0:
+ receiver(host, port, n);
+ return;
+ case -1:
+ ERRX(EXIT_FAILURE, "fork (%s)", strerror(errno));
+ default:
+ usleep(100);
+ sender(host, port, n);
+ return;
+ }
+}
+
+#ifdef TEST
+int
+main(int argc, char *argv[])
+{
+ const char *host, *port;
+ int c;
+ size_t n;
+
+ host = HOST_V4;
+ port = PORT_V4;
+ n = TOTAL;
+
+ while ((c = getopt(argc, argv, "46dmn:")) != -1)
+ switch (c) {
+ case '4':
+ host = HOST_V4;
+ port = PORT_V4;
+ break;
+ case '6':
+ host = HOST_V6;
+ port = PORT_V6;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'm':
+ host = HOST_V4MAPPED;
+ port = PORT_V4MAPPED;
+ break;
+ case 'n':
+ n = atoi(optarg);
+ break;
Home |
Main Index |
Thread Index |
Old Index