From: Radek Pazdera <rpazdera(a)redhat.com>
The `test_tools/' directory is a place for storing
various non-python tools that will later be used for
testing, such as programs in C, shell scripts etc.
This commit also adds first test tools - a set of
utilities, test setups and cases for validating
implementation of multicast/igmp in kernel.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
---
example_recipes/cmd_sequences/multicast/if.xml | 77 ++++++++
example_recipes/cmd_sequences/multicast/loop.xml | 70 +++++++
example_recipes/cmd_sequences/multicast/simple.xml | 33 ++++
example_recipes/cmd_sequences/multicast/ttl.xml | 112 ++++++++++++
test_tools/multicast/Makefile | 22 +++
test_tools/multicast/client/send_simple.c | 59 ++++++
test_tools/multicast/multicast_utils.h | 192 ++++++++++++++++++++
test_tools/multicast/offline/sockopt_if.c | 70 +++++++
test_tools/multicast/offline/sockopt_loop.c | 52 ++++++
test_tools/multicast/offline/sockopt_ttl.c | 79 ++++++++
test_tools/multicast/parameters.h | 152 ++++++++++++++++
test_tools/multicast/server/recv_simple.c | 50 +++++
test_tools/multicast/sockopt_utils.h | 176 ++++++++++++++++++
13 files changed, 1144 insertions(+), 0 deletions(-)
create mode 100644 example_recipes/cmd_sequences/multicast/if.xml
create mode 100644 example_recipes/cmd_sequences/multicast/loop.xml
create mode 100644 example_recipes/cmd_sequences/multicast/simple.xml
create mode 100644 example_recipes/cmd_sequences/multicast/ttl.xml
create mode 100644 test_tools/multicast/Makefile
create mode 100644 test_tools/multicast/client/send_simple.c
create mode 100644 test_tools/multicast/multicast_utils.h
create mode 100644 test_tools/multicast/offline/sockopt_if.c
create mode 100644 test_tools/multicast/offline/sockopt_loop.c
create mode 100644 test_tools/multicast/offline/sockopt_ttl.c
create mode 100644 test_tools/multicast/parameters.h
create mode 100644 test_tools/multicast/server/recv_simple.c
create mode 100644 test_tools/multicast/sockopt_utils.h
diff --git a/example_recipes/cmd_sequences/multicast/if.xml
b/example_recipes/cmd_sequences/multicast/if.xml
new file mode 100644
index 0000000..c7fec3f
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/if.xml
@@ -0,0 +1,77 @@
+<!-- Offline IP_MULTICAST_IF test -->
+<!-- Requires: 2 hosts
+ - [1] with one interface
+ - [2] with one interface
+ - -->
+
+<command_sequence>
+ <!-- IP_MULTICAST_IF sockopt conformance test -->
+ <command type="test" value="Multicast"
machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="sockopt_if" />
+
+ <!-- This condition doesn't pass yet because of a
+ bug in the syscal. #803202 on RedHat Bugzilla -->
+ <!-- <option name="condition" value="status ==
'pass'" /> -->
+ </options>
+ </command>
+
+ <!-- IP_MULTICAST_IF correct interfaces set -->
+ <command type="exec" machine_id="1" value="sleep 1"
/>
+ <command type="exec" machine_id="2" value="sleep 1"
/>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="0" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+ </options>
+ </command>
+
+ <command type="test" value="Multicast"
machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface"
value="['machines'][2]['netconfig'][1]['addresses'][0]"
/>
+
+ <option name="condition" value="packets_received >
0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- IP_MULTICAST_IF incorrect interfaces set -->
+ <command type="exec" machine_id="1" value="sleep 1"
/>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="1" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+ </options>
+ </command>
+
+ <command type="test" value="Multicast"
machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="interface" value="127.0.0.1" />
+
+ <option name="condition" value="packets_received == 0"
/>
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+</command_sequence>
diff --git a/example_recipes/cmd_sequences/multicast/loop.xml
b/example_recipes/cmd_sequences/multicast/loop.xml
new file mode 100644
index 0000000..7b155e1
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/loop.xml
@@ -0,0 +1,70 @@
+<!-- Offline IP_MULTICAST_LOOP test -->
+<!-- Requires: 1 hosts with at least two interfaces -->
+
+<command_sequence>
+ <!-- IP_MULTICAST_LOOP sockopt conformance test -->
+ <command type="test" value="Multicast"
machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="sockopt_loop" />
+ <option name="condition" value="status ==
'pass'" />
+ </options>
+ </command>
+
+ <!-- IP_MULTICAST_LOOP enabled -->
+ <command type="exec" machine_id="1" value="sleep 1"
/>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="loop" value="1" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+ </options>
+ </command>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+
+ <option name="condition" value="packets_received >
0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- IP_MULTICAST_LOOP disabled -->
+ <command type="exec" machine_id="1" value="sleep 1"
/>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="loop" value="0" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+ </options>
+ </command>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+
+ <option name="condition" value="packets_received == 0"
/>
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+</command_sequence>
diff --git a/example_recipes/cmd_sequences/multicast/simple.xml
b/example_recipes/cmd_sequences/multicast/simple.xml
new file mode 100644
index 0000000..236558b
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/simple.xml
@@ -0,0 +1,33 @@
+<!-- Requires: 2 hosts with at least one interface -->
+<!-- ['machines'][2]['netconfig'][1]['addresses'][0] -->
+
+<command_sequence>
+ <command type="exec" machine_id="1" value="sleep 1"
/>
+ <command type="exec" machine_id="2" value="sleep 1"
/>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+ </options>
+ </command>
+
+ <command type="test" value="Multicast"
machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <!-- <option name="interface"
value="192.168.122.179" /> -->
+ <option type="recipe_eval" name="interface"
value="['machines'][2]['netconfig'][1]['addresses'][0]"
/>
+
+ <option name="condition" value="packets_received >
0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+</command_sequence>
diff --git a/example_recipes/cmd_sequences/multicast/ttl.xml
b/example_recipes/cmd_sequences/multicast/ttl.xml
new file mode 100644
index 0000000..ae55228
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/ttl.xml
@@ -0,0 +1,112 @@
+<!-- Offline IP_MULTICAST_TTL test -->
+<!-- Requires: 2 hosts
+ - [1] with one interface
+ - [2] with one interface
+ - -->
+
+<command_sequence>
+ <!-- IP_MULTICAST_TTL sockopt conformance test -->
+ <command type="test" value="Multicast"
machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="sockopt_ttl" />
+ <option name="condition" value="status ==
'pass'" />
+ </options>
+ </command>
+
+ <!-- IP_MULTICAST_TTL = 0, looped on one host -->
+ <command type="exec" machine_id="1" value="sleep 1"
/>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="0" />
+ <option name="loop" value="1" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+ </options>
+ </command>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+
+ <option name="condition" value="packets_received >
0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- IP_MULTICAST_TTL = 0 between 2 hosts -->
+ <!-- KNOWN BUG: according to the specs, packets
+ with TTL=0 should not leave the host.
+
+ Well it does, it's an intentional hack for some
+ apps [1].
+
+
http://www.spinics.net/lists/netdev/msg183704.html
+ -->
+ <command type="exec" machine_id="1" value="sleep 1"
/>
+ <command type="exec" machine_id="2" value="sleep 1"
/>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="0" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+ </options>
+ </command>
+
+ <command type="test" value="Multicast"
machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface"
value="['machines'][2]['netconfig'][1]['addresses'][0]"
/>
+
+ <option name="condition" value="packets_received >
0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- IP_MULTICAST_TTL = 1 between 2 hosts -->
+ <command type="exec" machine_id="1" value="sleep 1"
/>
+
+ <command type="test" value="Multicast"
machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="1" />
+ <option type="recipe_eval" name="interface"
value="['machines'][1]['netconfig'][1]['addresses'][0]"
/>
+ </options>
+ </command>
+
+ <command type="test" value="Multicast"
machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface"
value="['machines'][2]['netconfig'][1]['addresses'][0]"
/>
+
+ <option name="condition" value="packets_received >
0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+</command_sequence>
diff --git a/test_tools/multicast/Makefile b/test_tools/multicast/Makefile
new file mode 100644
index 0000000..cb6ef4f
--- /dev/null
+++ b/test_tools/multicast/Makefile
@@ -0,0 +1,22 @@
+CC=gcc
+TOOLS_DIR=.
+CFLAGS=-Wall -Wextra -I$(TOOLS_DIR)
+
+SENDERS=send_simple
+RECEIVERS=recv_simple
+OFFLINE=sockopt_loop sockopt_ttl sockopt_if
+
+all: $(SENDERS) $(RECEIVERS) $(OFFLINE)
+
+$(SENDERS):
+ $(CC) $(CFLAGS) -o $@ client/$@.c
+
+$(RECEIVERS):
+ $(CC) $(CFLAGS) -o $@ server/$@.c
+
+$(OFFLINE):
+ $(CC) $(CFLAGS) -o $@ offline/$@.c
+
+clean:
+ rm -f $(SENDERS) $(RECEIVERS) $(OFFLINE)
+
diff --git a/test_tools/multicast/client/send_simple.c
b/test_tools/multicast/client/send_simple.c
new file mode 100644
index 0000000..2aaecd0
--- /dev/null
+++ b/test_tools/multicast/client/send_simple.c
@@ -0,0 +1,59 @@
+/*
+ * send_simple.c - simple sender setup for multicast tests
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define SEND
+#include "multicast_utils.h"
+
+int main(int argc, char** argv)
+{
+ struct parameters params;
+ parse_args(argc, argv, ¶ms);
+
+ int sockfd = init_out_socket(¶ms);
+
+ /* Sockopts setup */
+ if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
+ &(params.loop), sizeof(params.loop)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
+ &(params.ttl), sizeof(params.ttl)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF,
+ &(params.interface), sizeof(params.interface)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ int num_sent = 0;
+ num_sent = send_data(sockfd, params.multiaddr, params.port,
+ params.duration, params.delay);
+
+ printf("packets_sent=%d\n", num_sent);
+
+ return EXIT_SUCCESS;
+}
diff --git a/test_tools/multicast/multicast_utils.h
b/test_tools/multicast/multicast_utils.h
new file mode 100644
index 0000000..35a4e23
--- /dev/null
+++ b/test_tools/multicast/multicast_utils.h
@@ -0,0 +1,192 @@
+/*
+ * multicast_utils.h - common tools for kernel multicast tests
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __MULTICAST_UTILS_H__
+#define __MULTICAST_UTILS_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+
+#include <signal.h>
+#include <time.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#if !defined(SEND) && !defined(RECEIVE)
+#error "At least one of SEND/RECEIVE macros must be defined!"
+#endif
+
+#include "parameters.h"
+
+#define MESSAGE "Hello world!"
+
+int __verbosity = 0;
+
+/* Verbose print */
+#define printv(args...) \
+ if (__verbosity > 0) \
+ { \
+ printf(args); \
+ fflush(stdout); \
+ }
+
+/** Initiailze socket for receiving multicast data */
+int init_in_socket(struct in_addr multiaddr, short port)
+{
+ int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ perror("socket()");
+ exit(EXIT_FAILURE);
+ }
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr = multiaddr;
+ memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero));
+
+ if (bind(sockfd, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
+ perror("bind()");
+ exit(EXIT_FAILURE);
+ }
+
+ return sockfd;
+}
+
+/** Initialize socket for sending multicast data */
+int init_out_socket()
+{
+ int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ perror("socket()");
+ exit(EXIT_FAILURE);
+ }
+
+ return sockfd;
+}
+
+/** Close a socket */
+void free_socket(int sockfd)
+{
+ close(sockfd);
+}
+
+/** Wait for data up to `duration' seconds */
+int wait_for_data(int sockfd, int duration, int packet_limit)
+{
+ const char message[] = MESSAGE;
+ char buffer[] = MESSAGE;
+ memset(buffer, 0, sizeof(buffer));
+
+ int num_received = 0;
+
+ fd_set receive_fd_set;
+ struct timeval timeout;
+
+ time_t deadline = time(NULL) + duration;
+
+ printv("Receiving\n");
+
+ while (1) {
+ FD_ZERO(&receive_fd_set);
+ FD_SET(sockfd, &receive_fd_set);
+
+ if (duration == 0) {
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ } else {
+ time_t now = time(NULL);
+ if ((deadline - now) <= 0)
+ break;
+
+ timeout.tv_sec = deadline - now;
+ timeout.tv_usec = 0;
+ }
+
+
+ if (select(sockfd + 1, &receive_fd_set, NULL, NULL, &timeout) > 0) {
+ recv(sockfd, buffer, sizeof(buffer), 0);
+ if (strncmp(message, buffer, sizeof(buffer)) == 0) {
+ num_received++;
+
+ printv(".");
+ if (!(num_received % 10))
+ printv("\n");
+
+ if (packet_limit > 0 && num_received > packet_limit)
+ break;
+ }
+ }
+ }
+
+ printv("\n");
+
+ return num_received;
+}
+
+/** Send data for specified amount of time */
+int send_data(int sockfd, struct in_addr multiaddr, short port,
+ int duration, double delay)
+{
+ const char message[] = MESSAGE;
+ int i = 0;
+
+ struct sockaddr_in addr;
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr = multiaddr;
+ addr.sin_port = htons(port);
+ memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero));
+
+ struct timespec delay_value;
+ delay_value.tv_sec = 0;
+ delay_value.tv_nsec = delay * 999999999;
+
+ printv("Sending...\n");
+
+ time_t started_at = time(NULL);
+ while (duration == 0 || (time(NULL) - started_at) < duration) {
+ i++;
+ sendto(sockfd, message, strlen(message), 0,
+ (struct sockaddr*) &addr, sizeof(addr));
+
+ printv(".");
+ if (!(i % 10))
+ printv("\n");
+
+ nanosleep(&delay_value, NULL);
+ }
+
+ printv("\n");
+
+ return i;
+}
+
+#endif
diff --git a/test_tools/multicast/offline/sockopt_if.c
b/test_tools/multicast/offline/sockopt_if.c
new file mode 100644
index 0000000..db52e46
--- /dev/null
+++ b/test_tools/multicast/offline/sockopt_if.c
@@ -0,0 +1,70 @@
+/*
+ * sockopt_if.c - IP_MULTICAST_IF socket option test
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "sockopt_utils.h"
+
+
+void test_if()
+{
+ struct in_addr address;
+ size_t size = sizeof(address);
+
+ address.s_addr = INADDR_ANY;
+ test_getsockopt("IP_MULTICAST_IF default value",
+ IP_MULTICAST_IF, &address, size);
+
+ inet_pton(AF_INET, "127.0.0.1", &address);
+ test_sockopt_value("IP_MULTICAST_IF set to 127.0.0.1",
+ IP_MULTICAST_IF, &address, size);
+
+ struct ip_mreqn mreqn;
+ mreqn.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreqn.imr_address.s_addr = INADDR_ANY;
+ mreqn.imr_ifindex = 0;
+
+ test_sockopt_value("IP_MULTICAST_IF set to INADDR_ANY",
+ IP_MULTICAST_IF, &mreqn, sizeof(mreqn));
+
+ mreqn.imr_address.s_addr = 0x0100007f;
+ test_sockopt_value("IP_MULTICAST_IF set to 127.0.0.1",
+ IP_MULTICAST_IF, &mreqn, sizeof(mreqn));
+
+
+ /* Errors */
+ test_setsockopt_error("IP_MULTICAST_IF bad optlen",
+ IP_MULTICAST_IF, &address, 3, EINVAL);
+
+ inet_pton(AF_INET, "238.0.10.0", &address);
+ test_setsockopt_error("IP_MULTICAST_IF address 238.0.10.0",
+ IP_MULTICAST_IF, &address,
+ sizeof(address), EADDRNOTAVAIL);
+}
+
+int main()
+{
+ initialize();
+
+ test_if();
+
+ report_and_exit();
+ return 0;
+}
diff --git a/test_tools/multicast/offline/sockopt_loop.c
b/test_tools/multicast/offline/sockopt_loop.c
new file mode 100644
index 0000000..88050a5
--- /dev/null
+++ b/test_tools/multicast/offline/sockopt_loop.c
@@ -0,0 +1,52 @@
+/*
+ * sockopt_loop.c - IP_MULTICAST_LOOP socket option test
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "sockopt_utils.h"
+
+
+void test_loop()
+{
+ int value;
+ size_t size = sizeof(value);
+
+ value = 1;
+ test_getsockopt("IP_MULTICAST_LOOP default value",
+ IP_MULTICAST_LOOP, &value, size);
+
+ value = 0;
+ test_sockopt_value("IP_MULTICAST_LOOP set to zero",
+ IP_MULTICAST_LOOP, &value, size);
+
+ /* Errors */
+ test_setsockopt_error("IP_MULTICAST_LOOP bad optlen",
+ IP_MULTICAST_LOOP, &value, 0, EINVAL);
+}
+
+int main()
+{
+ initialize();
+
+ test_loop();
+
+ report_and_exit();
+ return 0;
+}
diff --git a/test_tools/multicast/offline/sockopt_ttl.c
b/test_tools/multicast/offline/sockopt_ttl.c
new file mode 100644
index 0000000..94419eb
--- /dev/null
+++ b/test_tools/multicast/offline/sockopt_ttl.c
@@ -0,0 +1,79 @@
+/*
+ * sockopt_ttl.c - IP_MULTICAST_TTL socket option test
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "sockopt_utils.h"
+
+
+void test_ttl()
+{
+ int value;
+ size_t size = sizeof(value);
+
+ value = 1;
+ test_getsockopt("IP_MULTICAST_TTL default value",
+ IP_MULTICAST_TTL, &value, size);
+
+ value = 0;
+ test_sockopt_value("IP_MULTICAST_TTL set to zero",
+ IP_MULTICAST_TTL, &value, size);
+
+ value = 64;
+ test_sockopt_value("IP_MULTICAST_TTL set to 64",
+ IP_MULTICAST_TTL, &value, size);
+
+ value = 255;
+ test_sockopt_value("IP_MULTICAST_TTL set to 255",
+ IP_MULTICAST_TTL, &value, size);
+
+
+ /*
+ * Special case:
+ * For some reason kernel accepts
+ * TTL = -1 and takes it as if it were 1
+ */
+ value = -1;
+ test_setsockopt("IP_MULTICAST_TTL set to -1",
+ IP_MULTICAST_TTL, &value, size);
+
+ value = 1;
+ test_getsockopt("IP_MULTICAST_TTL set to 1",
+ IP_MULTICAST_TTL, &value, size);
+
+
+ /* Errors */
+ value = 500;
+ test_setsockopt_error("IP_MULTICAST_TTL set to 500",
+ IP_MULTICAST_TTL, &value, size, EINVAL);
+
+ test_setsockopt_error("IP_MULTICAST_TTL bad optlen",
+ IP_MULTICAST_TTL, &value, 0, EINVAL);
+}
+
+int main()
+{
+ initialize();
+
+ test_ttl();
+
+ report_and_exit();
+ return 0;
+}
diff --git a/test_tools/multicast/parameters.h b/test_tools/multicast/parameters.h
new file mode 100644
index 0000000..859a020
--- /dev/null
+++ b/test_tools/multicast/parameters.h
@@ -0,0 +1,152 @@
+/*
+ * parameters.h - common code for parsing sender/receiver parameters
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <signal.h>
+#include <time.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern int __verbosity;
+
+/** Structure that carries test parameters */
+struct parameters
+{
+ int duration; /* seconds */
+
+ struct in_addr multiaddr;
+ short port;
+ struct in_addr interface;
+
+#ifdef RECEIVE
+ struct in_addr sourceaddr;
+#endif
+
+#ifdef SEND
+ double delay;
+ int ttl;
+ int loop;
+#endif
+};
+
+/** Initialize parameters struct with default values. */
+void default_parameters(struct parameters* params)
+{
+ params->duration = 10;
+ params->port = 0;
+ memset(¶ms->multiaddr, 0, sizeof(struct in_addr));
+ memset(¶ms->interface, 0, sizeof(struct in_addr));
+#ifdef RECEIVE
+ memset(¶ms->sourceaddr, 0, sizeof(struct in_addr));
+#endif
+
+#ifdef SEND
+ params->delay = 0.1;
+ params->ttl = 1;
+ params->loop = 1;
+#endif
+}
+
+/** Generic function for parsing arguments */
+void parse_args(int argc, char** argv, struct parameters* args)
+{
+#ifdef SEND
+ static const char* opts = "d:a:p:i:f:l:t:v";
+#endif
+
+#ifdef RECEIVE
+ static const char* opts = "d:a:p:s:i:v";
+#endif
+
+ static struct option long_options[] =
+ {
+ {"duration", required_argument, NULL, 'd'},
+ {"multicast_address", required_argument, NULL, 'a'},
+ {"port", required_argument, NULL, 'p'},
+ {"interface", required_argument, NULL, 'i'},
+ {"verbose", no_argument, NULL, 'v'},
+#ifdef RECEIVE
+ {"source_address", required_argument, NULL, 's'},
+#endif
+
+#ifdef SEND
+ {"delay", required_argument, NULL, 'f'},
+ {"ttl", required_argument, NULL, 't'},
+ {"loop", required_argument, NULL, 'l'},
+#endif
+ {0, 0, NULL, 0}
+ };
+
+ default_parameters(args);
+
+ int opt;
+ int option_index = 0;
+ while((opt = getopt_long(argc, argv, opts, long_options,
+ &option_index)) != -1) {
+ switch (opt) {
+ case 'd':
+ args->duration = atoi(optarg);
+ break;
+ case 'a':
+ inet_pton(AF_INET, optarg, &(args->multiaddr));
+ break;
+ case 'p':
+ args->port = atoi(optarg);
+ break;
+ case 'i':
+ inet_pton(AF_INET, optarg, &(args->interface));
+ break;
+ case 'v':
+ __verbosity = 1;
+ break;
+#ifdef RECEIVE
+ case 's':
+ inet_pton(AF_INET, optarg, &(args->sourceaddr));
+ break;
+#endif
+
+#ifdef SEND
+ case 'f':
+ args->delay = atof(optarg);
+ break;
+ case 't':
+ args->ttl = atoi(optarg);
+ break;
+ case 'l':
+ args->loop = atoi(optarg);
+ break;
+#endif
+ default: /* '?' */
+ printf("%s: invalid test options\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
diff --git a/test_tools/multicast/server/recv_simple.c
b/test_tools/multicast/server/recv_simple.c
new file mode 100644
index 0000000..5ea5087
--- /dev/null
+++ b/test_tools/multicast/server/recv_simple.c
@@ -0,0 +1,50 @@
+/*
+ * recv_simple.c - simple receiver setup for multicast tests
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define RECEIVE
+#include "multicast_utils.h"
+
+int main(int argc, char** argv)
+{
+ struct parameters params;
+ parse_args(argc, argv, ¶ms);
+
+ int sockfd = init_in_socket(params.multiaddr, params.port);
+
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr = params.multiaddr;
+ mreq.imr_interface = params.interface;
+
+ int num_recv = 0;
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &(mreq), sizeof(mreq)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ num_recv = wait_for_data(sockfd, params.duration, 0);
+
+ printf("packets_received=%d\n", num_recv);
+
+ return EXIT_SUCCESS;
+}
diff --git a/test_tools/multicast/sockopt_utils.h b/test_tools/multicast/sockopt_utils.h
new file mode 100644
index 0000000..587b8dc
--- /dev/null
+++ b/test_tools/multicast/sockopt_utils.h
@@ -0,0 +1,176 @@
+/*
+ * sockopt_utils.h - common tools for writing sockopt conformance tests
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __SOCKOPT_UTILS_H__
+#define __SOCKOPT_UTILS_H__
+
+#define __SUCCESS_CODE 0
+#define __FAILURE_CODE 1
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int __test_status = 1;
+int __sockfd;
+
+void fail()
+{
+ __test_status = 0;
+}
+
+void report_and_exit()
+{
+ close(__sockfd);
+
+ if (__test_status) {
+ printf("status=pass\n");
+ exit(__SUCCESS_CODE);
+ } else {
+ printf("status=fail\n");
+ exit(__FAILURE_CODE);
+ }
+}
+
+void error_exit(char* what)
+{
+ int code = errno;
+ printf("error_message=%s %s\n", what, strerror(code));
+ fail();
+ report_and_exit();
+}
+
+void initialize()
+{
+ __sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (__sockfd < 0)
+ error_exit("socket()");
+}
+
+void test_getsockopt(char* test_name, int optname, void *expected_optval,
+ socklen_t expected_optlen)
+{
+ int status;
+ socklen_t size = expected_optlen;
+ void* value = malloc(size);
+
+ if (value == NULL)
+ error_exit("malloc()");
+
+ memset(value, 0, size);
+
+ status = getsockopt(__sockfd, IPPROTO_IP, optname, value, &size);
+ if (status < 0)
+ error_exit("getsockopt()");
+
+ if (expected_optlen != size) {
+ printf("%s=fail: size of the returned struct differ\n", test_name);
+ fail();
+ } else {
+ socklen_t i;
+ for (i = 0; i < size; i++)
+ if (((char*) value)[i] != ((char*) expected_optval)[i])
+ {
+ free(value);
+ printf("%s=fail: received value of the option "
+ "differs from expected one\n", test_name);
+ fail();
+ return;
+ }
+
+ printf("%s=pass\n", test_name);
+ }
+
+ free(value);
+}
+
+
+void test_setsockopt(char* test_name, int optname, void *optval,
+ socklen_t optlen)
+{
+ int status;
+
+ status = setsockopt(__sockfd, IPPROTO_IP, optname, optval, optlen);
+ if (status < 0)
+ error_exit("setsockopt()");
+
+ printf("%s=pass\n", test_name);
+}
+
+void test_sockopt_value(char* test_name, int optname,
+ void *optval, socklen_t optlen)
+{
+ test_setsockopt(test_name, optname, optval, optlen);
+ test_getsockopt(test_name, optname, optval, optlen);
+}
+
+void test_setsockopt_error(char* test_name, int optname, void *optval,
+ socklen_t optlen, int expected_errorcode)
+{
+ int status;
+
+ status = setsockopt(__sockfd, IPPROTO_IP, optname, optval, optlen);
+ if (status < 0) {
+ if (errno != expected_errorcode) {
+ printf("%s=fail: error codes don't "
+ "match (expected %d, got %d)\n", test_name,
+ expected_errorcode, errno);
+ fail();
+ } else {
+ printf("%s=pass\n", test_name);
+ }
+ } else {
+ printf("%s=fail: no error occured\n", test_name);
+ fail();
+ }
+}
+
+void test_getsockopt_error(char* test_name, int optname, void *optval,
+ socklen_t optlen, int expected_errorcode)
+{
+ int status;
+ socklen_t size = optlen;
+
+ status = getsockopt(__sockfd, IPPROTO_IP, optname, optval, &size);
+ if (status < 0) {
+ if (errno != expected_errorcode) {
+ printf("%s=fail: error codes don't "
+ "match (expected %d, got %d)\n", test_name,
+ expected_errorcode, errno);
+ fail();
+ } else {
+ printf("%s=pass\n", test_name);
+ }
+ } else {
+ printf("%s=fail: no error occured\n", test_name);
+ fail();
+ }
+}
+
+#endif
+
--
1.7.7.6