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/fa6d80ea09d3
branches:  trunk
changeset: 803060:fa6d80ea09d3
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 3e6a5944815f -r fa6d80ea09d3 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 3e6a5944815f -r fa6d80ea09d3 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 3e6a5944815f -r fa6d80ea09d3 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