commit 1b1a3a5c5860071b3fcf729ae379df0df628e871 Author: Radek Pazdera rpazdera@redhat.com Date: Thu Apr 5 14:56:39 2012 +0200
multicast: Adding new folder for test tools
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@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 | 21 ++ 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 | 175 ++++++++++++++++++ 13 files changed, 1142 insertions(+), 0 deletions(-) --- 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..47af8f5 --- /dev/null +++ b/test_tools/multicast/Makefile @@ -0,0 +1,21 @@ +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..2651c36 --- /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@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..25d0c38 --- /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@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..ff5bd51 --- /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@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..fdf7478 --- /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@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..293bbe5 --- /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@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..6a313ec --- /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@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..c4d045c --- /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@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..6486f71 --- /dev/null +++ b/test_tools/multicast/sockopt_utils.h @@ -0,0 +1,175 @@ +/* + * sockopt_utils.h - common tools for writing sockopt conformance tests + * Copyright (C) 2012 Red Hat Inc. + * + * Author: Radek Pazdera (rpazdera@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
lnst-developers@lists.fedorahosted.org