123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include "../sockcreator.h"
- #include <util/unittests/fork.h>
- #include <util/io/fd.h>
- #include <gtest/gtest.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <unistd.h>
- #include <cstring>
- #include <cerrno>
- using namespace isc::socket_creator;
- using namespace isc::util::unittests;
- using namespace isc::util::io;
- namespace {
- /*
- * Generic version of the creation of socket test. It just tries to
- * create the socket and checks the result is not negative (eg.
- * it is valid descriptor) and that it can listen.
- *
- * This is a macro so ASSERT_* does abort the TEST, not just the
- * function inside.
- */
- #define TEST_ANY_CREATE(SOCK_TYPE, ADDR_TYPE, ADDR_FAMILY, FAMILY_FIELD, \
- ADDR_SET, CHECK_SOCK) \
- do { \
- /*
- * This should create an address that binds on all interfaces
- * and lets the OS choose a free port.
- */ \
- struct ADDR_TYPE addr; \
- memset(&addr, 0, sizeof addr); \
- ADDR_SET(addr); \
- addr.FAMILY_FIELD = ADDR_FAMILY; \
- struct sockaddr *addr_ptr = static_cast<struct sockaddr *>( \
- static_cast<void *>(&addr)); \
- \
- int socket = get_sock(SOCK_TYPE, addr_ptr, sizeof addr); \
- /* Provide even nice error message. */ \
- ASSERT_GE(socket, 0) << "Couldn't create a socket of type " \
- #SOCK_TYPE " and family " #ADDR_FAMILY ", failed with " \
- << socket << " and error " << strerror(errno); \
- CHECK_SOCK(ADDR_TYPE, socket); \
- int on; \
- socklen_t len(sizeof(on)); \
- ASSERT_EQ(0, getsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &on, &len));\
- ASSERT_EQ(1, on); \
- if (ADDR_FAMILY == AF_INET6) { \
- ASSERT_EQ(0, getsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, &on, \
- &len)); \
- ASSERT_EQ(1, on); \
- } \
- EXPECT_EQ(0, close(socket)); \
- } while (0)
- // Just helper macros
- #define INADDR_SET(WHAT) do { WHAT.sin_addr.s_addr = INADDR_ANY; } while (0)
- #define IN6ADDR_SET(WHAT) do { WHAT.sin6_addr = in6addr_loopback; } while (0)
- // If the get_sock returned something useful, listen must work
- #define TCP_CHECK(UNUSED, SOCKET) do { \
- EXPECT_EQ(0, listen(SOCKET, 1)); \
- } while (0)
- // More complicated with UDP, so we send a packet to ourselfs and se if it
- // arrives
- #define UDP_CHECK(ADDR_TYPE, SOCKET) do { \
- struct ADDR_TYPE addr; \
- memset(&addr, 0, sizeof addr); \
- struct sockaddr *addr_ptr = static_cast<struct sockaddr *>( \
- static_cast<void *>(&addr)); \
- \
- socklen_t len = sizeof addr; \
- ASSERT_EQ(0, getsockname(SOCKET, addr_ptr, &len)); \
- ASSERT_EQ(5, sendto(SOCKET, "test", 5, 0, addr_ptr, sizeof addr)) << \
- "Send failed with error " << strerror(errno) << " on socket " << \
- SOCKET; \
- char buffer[5]; \
- ASSERT_EQ(5, recv(SOCKET, buffer, 5, 0)) << \
- "Recv failed with error " << strerror(errno) << " on socket " << \
- SOCKET; \
- EXPECT_STREQ("test", buffer); \
- } while (0)
- /*
- * Several tests to ensure we can create the sockets.
- */
- TEST(get_sock, udp4_create) {
- TEST_ANY_CREATE(SOCK_DGRAM, sockaddr_in, AF_INET, sin_family, INADDR_SET,
- UDP_CHECK);
- }
- TEST(get_sock, tcp4_create) {
- TEST_ANY_CREATE(SOCK_STREAM, sockaddr_in, AF_INET, sin_family, INADDR_SET,
- TCP_CHECK);
- }
- TEST(get_sock, udp6_create) {
- TEST_ANY_CREATE(SOCK_DGRAM, sockaddr_in6, AF_INET6, sin6_family,
- IN6ADDR_SET, UDP_CHECK);
- }
- TEST(get_sock, tcp6_create) {
- TEST_ANY_CREATE(SOCK_STREAM, sockaddr_in6, AF_INET6, sin6_family,
- IN6ADDR_SET, TCP_CHECK);
- }
- /*
- * Try to ask the get_sock function some nonsense and test if it
- * is able to report error.
- */
- TEST(get_sock, fail_with_nonsense) {
- struct sockaddr addr;
- memset(&addr, 0, sizeof addr);
- ASSERT_LT(get_sock(0, &addr, sizeof addr), 0);
- }
- /*
- * Helper functions to pass to run during testing.
- */
- int
- get_sock_dummy(const int type, struct sockaddr *addr, const socklen_t)
- {
- int result(0);
- int port(0);
- /*
- * We encode the type and address family into the int and return it.
- * Lets ignore the port and address for now
- * First bit is 1 if it is known type. Second tells if TCP or UDP.
- * The familly is similar - third bit is known address family,
- * the fourth is the family.
- */
- switch (type) {
- case SOCK_STREAM:
- result += 1;
- break;
- case SOCK_DGRAM:
- result += 3;
- break;
- }
- switch (addr->sa_family) {
- case AF_INET:
- result += 4;
- port = static_cast<struct sockaddr_in *>(
- static_cast<void *>(addr))->sin_port;
- break;
- case AF_INET6:
- result += 12;
- port = static_cast<struct sockaddr_in6 *>(
- static_cast<void *>(addr))->sin6_port;
- break;
- }
- /*
- * The port should be 0xffff. If it's not, we change the result.
- * The port of 0xbbbb means bind should fail and 0xcccc means
- * socket should fail.
- */
- if (port != 0xffff) {
- errno = 0;
- if (port == 0xbbbb) {
- return -2;
- } else if (port == 0xcccc) {
- return -1;
- } else {
- result += 16;
- }
- }
- return result;
- }
- int
- send_fd_dummy(const int destination, const int what)
- {
- /*
- * Make sure it is 1 byte so we know the length. We do not use more during
- * the test anyway.
- */
- char fd_data(what);
- if (!write_data(destination, &fd_data, 1)) {
- return -1;
- } else {
- return 0;
- }
- }
- /*
- * Generic test that it works, with various inputs and outputs.
- * It uses different functions to create the socket and send it and pass
- * data to it and check it returns correct data back, to see if the run()
- * parses the commands correctly.
- */
- void run_test(const char *input_data, const size_t input_size,
- const char *output_data, const size_t output_size,
- bool should_succeed = true)
- {
- // Prepare the input feeder and output checker processes
- int input_fd(0), output_fd(0);
- pid_t input(provide_input(&input_fd, input_data, input_size)),
- output(check_output(&output_fd, output_data, output_size));
- ASSERT_NE(-1, input) << "Couldn't start input feeder";
- ASSERT_NE(-1, output) << "Couldn't start output checker";
- // Run the body
- int result(run(input_fd, output_fd, get_sock_dummy, send_fd_dummy));
- // Close the pipes
- close(input_fd);
- close(output_fd);
- // Did it run well?
- if (should_succeed) {
- EXPECT_EQ(0, result);
- } else {
- EXPECT_NE(0, result);
- }
- // Check the subprocesses say everything is OK too
- EXPECT_TRUE(process_ok(input));
- EXPECT_TRUE(process_ok(output));
- }
- /*
- * Check it terminates successfully when asked to.
- */
- TEST(run, terminate) {
- run_test("T", 1, NULL, 0);
- }
- /*
- * Check it rejects incorrect input.
- */
- TEST(run, bad_input) {
- run_test("XXX", 3, "FI", 2, false);
- }
- /*
- * Check it correctly parses queries to create sockets.
- */
- TEST(run, sockets) {
- run_test(
- "SU4\xff\xff\0\0\0\0" // This has 9 bytes
- "ST4\xff\xff\0\0\0\0" // This has 9 bytes
- "ST6\xff\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // This has 21 bytes
- "SU6\xff\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // This has 21 bytes
- "T", 61,
- "S\x07S\x05S\x0dS\x0f", 8);
- }
- /*
- * Check if failures of get_socket are handled correctly.
- */
- TEST(run, bad_sockets) {
- // We need to construct the answer, but it depends on int length.
- size_t int_len(sizeof(int));
- size_t result_len(4 + 2 * int_len);
- char result[4 + sizeof(int) * 2];
- // Both errno parts should be 0
- memset(result, 0, result_len);
- // Fill the 2 control parts
- strcpy(result, "EB");
- strcpy(result + 2 + int_len, "ES");
- // Run the test
- run_test(
- "SU4\xbb\xbb\0\0\0\0"
- "SU4\xcc\xcc\0\0\0\0"
- "T", 19,
- result, result_len);
- }
- }
|