sockcreator_tests.cc 8.33 KB
Newer Older
1
// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
Michal Vaner's avatar
Michal Vaner committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//
// 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"

Michal Vaner's avatar
Michal Vaner committed
17
18
19
#include <util/unittests/fork.h>
#include <util/io/fd.h>

Michal Vaner's avatar
Michal Vaner committed
20
21
22
23
#include <gtest/gtest.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
Michal Vaner's avatar
Michal Vaner committed
24
#include <unistd.h>
Michal Vaner's avatar
Michal Vaner committed
25
26
27
28
#include <cstring>
#include <cerrno>

using namespace isc::socket_creator;
Michal Vaner's avatar
Michal Vaner committed
29
30
using namespace isc::util::unittests;
using namespace isc::util::io;
Michal Vaner's avatar
Michal Vaner committed
31
32
33
34
35
36
37
38
39
40
41

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.
 */
42
43
#define TEST_ANY_CREATE(SOCK_TYPE, ADDR_TYPE, ADDR_FAMILY, FAMILY_FIELD, \
    ADDR_SET, CHECK_SOCK) \
Michal Vaner's avatar
Michal Vaner committed
44
45
46
47
48
49
50
51
    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); \
52
        addr.FAMILY_FIELD = ADDR_FAMILY; \
Michal Vaner's avatar
Michal Vaner committed
53
54
55
56
57
58
59
        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 " \
60
            << socket << " and error " << strerror(errno); \
Michal Vaner's avatar
Michal Vaner committed
61
62
        CHECK_SOCK(ADDR_TYPE, socket); \
        EXPECT_EQ(0, close(socket)); \
Michal Vaner's avatar
Michal Vaner committed
63
    } while (0)
Michal Vaner's avatar
Michal Vaner committed
64
65

// Just helper macros
Michal Vaner's avatar
Michal Vaner committed
66
67
#define INADDR_SET(WHAT) do { WHAT.sin_addr.s_addr = INADDR_ANY; } while (0)
#define IN6ADDR_SET(WHAT) do { WHAT.sin6_addr = in6addr_any; } while (0)
Michal Vaner's avatar
Michal Vaner committed
68
69
70
// If the get_sock returned something useful, listen must work
#define TCP_CHECK(UNUSED, SOCKET) do { \
        EXPECT_EQ(0, listen(SOCKET, 1)); \
Michal Vaner's avatar
Michal Vaner committed
71
    } while (0)
Michal Vaner's avatar
Michal Vaner committed
72
73
74
75
76
77
78
79
80
81
// 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)); \
82
83
84
        ASSERT_EQ(5, sendto(SOCKET, "test", 5, 0, addr_ptr, sizeof addr)) << \
            "Send failed with error " << strerror(errno) << " on socket " << \
            SOCKET; \
Michal Vaner's avatar
Michal Vaner committed
85
        char buffer[5]; \
86
87
88
        ASSERT_EQ(5, recv(SOCKET, buffer, 5, 0)) << \
            "Recv failed with error " << strerror(errno) << " on socket " << \
            SOCKET; \
Michal Vaner's avatar
Michal Vaner committed
89
        EXPECT_STREQ("test", buffer); \
Michal Vaner's avatar
Michal Vaner committed
90
    } while (0)
Michal Vaner's avatar
Michal Vaner committed
91
92
93
94
95

/*
 * Several tests to ensure we can create the sockets.
 */
TEST(get_sock, udp4_create) {
96
97
    TEST_ANY_CREATE(SOCK_DGRAM, sockaddr_in, AF_INET, sin_family, INADDR_SET,
        UDP_CHECK);
Michal Vaner's avatar
Michal Vaner committed
98
99
100
}

TEST(get_sock, tcp4_create) {
101
102
    TEST_ANY_CREATE(SOCK_STREAM, sockaddr_in, AF_INET, sin_family, INADDR_SET,
        TCP_CHECK);
Michal Vaner's avatar
Michal Vaner committed
103
104
105
}

TEST(get_sock, udp6_create) {
106
107
    TEST_ANY_CREATE(SOCK_DGRAM, sockaddr_in6, AF_INET6, sin6_family,
        IN6ADDR_SET, UDP_CHECK);
Michal Vaner's avatar
Michal Vaner committed
108
109
110
}

TEST(get_sock, tcp6_create) {
111
112
    TEST_ANY_CREATE(SOCK_STREAM, sockaddr_in6, AF_INET6, sin6_family,
        IN6ADDR_SET, TCP_CHECK);
Michal Vaner's avatar
Michal Vaner committed
113
114
115
116
117
118
119
}

/*
 * Try to ask the get_sock function some nonsense and test if it
 * is able to report error.
 */
TEST(get_sock, fail_with_nonsense) {
Michal Vaner's avatar
Michal Vaner committed
120
121
122
    struct sockaddr addr;
    memset(&addr, 0, sizeof addr);
    ASSERT_LT(get_sock(0, &addr, sizeof addr), 0);
Michal Vaner's avatar
Michal Vaner committed
123
124
}

Michal Vaner's avatar
Michal Vaner committed
125
126
127
128
/*
 * Helper functions to pass to run during testing.
 */
int
Michal Vaner's avatar
Michal Vaner committed
129
get_sock_dummy(const int type, struct sockaddr *addr, const socklen_t)
Michal Vaner's avatar
Michal Vaner committed
130
131
{
    int result(0);
Michal Vaner's avatar
Michal Vaner committed
132
    int port(0);
Michal Vaner's avatar
Michal Vaner committed
133
134
135
136
137
138
139
    /*
     * 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.
     */
Michal Vaner's avatar
Michal Vaner committed
140
    switch (type) {
Michal Vaner's avatar
Michal Vaner committed
141
142
143
144
145
146
147
        case SOCK_STREAM:
            result += 1;
            break;
        case SOCK_DGRAM:
            result += 3;
            break;
    }
Michal Vaner's avatar
Michal Vaner committed
148
    switch (addr->sa_family) {
Michal Vaner's avatar
Michal Vaner committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
        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.
     */
Michal Vaner's avatar
Michal Vaner committed
165
    if (port != 0xffff) {
Michal Vaner's avatar
Michal Vaner committed
166
        errno = 0;
Michal Vaner's avatar
Michal Vaner committed
167
        if (port == 0xbbbb) {
Michal Vaner's avatar
Michal Vaner committed
168
            return -2;
Michal Vaner's avatar
Michal Vaner committed
169
        } else if (port == 0xcccc) {
Michal Vaner's avatar
Michal Vaner committed
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
            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);
Michal Vaner's avatar
Michal Vaner committed
186
    if (!write_data(destination, &fd_data, 1)) {
Michal Vaner's avatar
Michal Vaner committed
187
        return -1;
Michal Vaner's avatar
Michal Vaner committed
188
189
190
    } else {
        return 0;
    }
Michal Vaner's avatar
Michal Vaner committed
191
192
193
194
195
196
197
198
199
200
201
202
203
}

/*
 * 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
Michal Vaner's avatar
Michal Vaner committed
204
    int input_fd(0), output_fd(0);
Michal Vaner's avatar
Michal Vaner committed
205
206
207
208
209
210
    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));
Michal Vaner's avatar
Michal Vaner committed
211
212
213
214
    // Close the pipes
    close(input_fd);
    close(output_fd);
    // Did it run well?
Michal Vaner's avatar
Michal Vaner committed
215
    if (should_succeed) {
Michal Vaner's avatar
Michal Vaner committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
        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);
259
    char result[4 + sizeof(int) * 2];
Michal Vaner's avatar
Michal Vaner committed
260
261
262
263
264
265
266
267
268
269
270
271
272
    // 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);
}

Michal Vaner's avatar
Michal Vaner committed
273
}