Module Name:    src
Committed By:   christos
Date:           Sat Oct 11 23:04:42 UTC 2014

Modified Files:
        src/tests/net: Makefile
Added Files:
        src/tests/net/mcast: Makefile t_mcast.c

Log Message:
add a multicast test (what to do with v6?)


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/tests/net/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/net/mcast/Makefile \
    src/tests/net/mcast/t_mcast.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/net/Makefile
diff -u src/tests/net/Makefile:1.18 src/tests/net/Makefile:1.19
--- src/tests/net/Makefile:1.18	Thu Sep 18 11:13:27 2014
+++ src/tests/net/Makefile	Sat Oct 11 19:04:42 2014
@@ -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")

Added files:

Index: src/tests/net/mcast/Makefile
diff -u /dev/null src/tests/net/mcast/Makefile:1.1
--- /dev/null	Sat Oct 11 19:04:42 2014
+++ src/tests/net/mcast/Makefile	Sat Oct 11 19:04:42 2014
@@ -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>
Index: src/tests/net/mcast/t_mcast.c
diff -u /dev/null src/tests/net/mcast/t_mcast.c:1.1
--- /dev/null	Sat Oct 11 19:04:42 2014
+++ src/tests/net/mcast/t_mcast.c	Sat Oct 11 19:04:42 2014
@@ -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;
+		default:
+			fprintf(stderr, "Usage: %s [-dm46] [-n <tot>]",
+			    getprogname());
+			return 1;
+		}
+
+	run(host, port, n);
+	return 0;
+}
+#else
+
+ATF_TC(inet4);
+ATF_TC_HEAD(inet4, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "Checks multicast for ipv4");
+}
+
+ATF_TC_BODY(inet4, tc)
+{
+	run(HOST_V4, PORT_V4, TOTAL);
+}
+
+ATF_TC(mappedinet4);
+ATF_TC_HEAD(mappedinet4, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "Checks multicast for mapped ipv4");
+}
+
+ATF_TC_BODY(mappedinet4, tc)
+{
+	run(HOST_V4MAPPED, PORT_V4MAPPED, TOTAL);
+}
+
+ATF_TC(inet6);
+ATF_TC_HEAD(inet6, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "Checks multicast for ipv6");
+}
+
+ATF_TC_BODY(inet6, tc)
+{
+	run(HOST_V6, PORT_V6, TOTAL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+        ATF_TP_ADD_TC(tp, inet4);
+        ATF_TP_ADD_TC(tp, mappedinet4);
+        ATF_TP_ADD_TC(tp, inet6);
+
+	return atf_no_error();
+}
+#endif

Reply via email to