sockcreator_tests.cc 9.3 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
        CHECK_SOCK(ADDR_TYPE, socket); \
62
63
        int on; \
        socklen_t len(sizeof(on)); \
64
65
        EXPECT_EQ(0, getsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &on, &len));\
        EXPECT_NE(0, on); \
66
        if (ADDR_FAMILY == AF_INET6) { \
67
            EXPECT_EQ(0, getsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, &on, \
68
                                    &len)); \
69
            EXPECT_NE(0, on); \
70
        } \
Michal Vaner's avatar
Michal Vaner committed
71
        EXPECT_EQ(0, close(socket)); \
Michal Vaner's avatar
Michal Vaner committed
72
    } while (0)
Michal Vaner's avatar
Michal Vaner committed
73
74

// Just helper macros
Michal Vaner's avatar
Michal Vaner committed
75
#define INADDR_SET(WHAT) do { WHAT.sin_addr.s_addr = INADDR_ANY; } while (0)
76
#define IN6ADDR_SET(WHAT) do { WHAT.sin6_addr = in6addr_loopback; } while (0)
Michal Vaner's avatar
Michal Vaner committed
77
78
79
// 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
80
    } while (0)
Michal Vaner's avatar
Michal Vaner committed
81
82
83
84
85
86
87
88
89
90
// 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)); \
91
92
93
        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
94
        char buffer[5]; \
95
96
97
        ASSERT_EQ(5, recv(SOCKET, buffer, 5, 0)) << \
            "Recv failed with error " << strerror(errno) << " on socket " << \
            SOCKET; \
Michal Vaner's avatar
Michal Vaner committed
98
        EXPECT_STREQ("test", buffer); \
Michal Vaner's avatar
Michal Vaner committed
99
    } while (0)
Michal Vaner's avatar
Michal Vaner committed
100
101
102
103
104

/*
 * Several tests to ensure we can create the sockets.
 */
TEST(get_sock, udp4_create) {
105
106
    TEST_ANY_CREATE(SOCK_DGRAM, sockaddr_in, AF_INET, sin_family, INADDR_SET,
        UDP_CHECK);
Michal Vaner's avatar
Michal Vaner committed
107
108
109
}

TEST(get_sock, tcp4_create) {
110
111
    TEST_ANY_CREATE(SOCK_STREAM, sockaddr_in, AF_INET, sin_family, INADDR_SET,
        TCP_CHECK);
Michal Vaner's avatar
Michal Vaner committed
112
113
114
}

TEST(get_sock, udp6_create) {
115
116
    TEST_ANY_CREATE(SOCK_DGRAM, sockaddr_in6, AF_INET6, sin6_family,
        IN6ADDR_SET, UDP_CHECK);
Michal Vaner's avatar
Michal Vaner committed
117
118
119
}

TEST(get_sock, tcp6_create) {
120
121
    TEST_ANY_CREATE(SOCK_STREAM, sockaddr_in6, AF_INET6, sin6_family,
        IN6ADDR_SET, TCP_CHECK);
Michal Vaner's avatar
Michal Vaner committed
122
123
124
125
126
127
128
}

/*
 * 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
129
130
131
    struct sockaddr addr;
    memset(&addr, 0, sizeof addr);
    ASSERT_LT(get_sock(0, &addr, sizeof addr), 0);
Michal Vaner's avatar
Michal Vaner committed
132
133
}

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

202
203
// Just ignore the fd and pretend success. We close invalid fds in the tests.
int
204
closeIgnore(int) {
205
206
207
    return (0);
}

Michal Vaner's avatar
Michal Vaner committed
208
209
210
211
212
213
214
215
/*
 * 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,
216
    bool should_succeed = true, const close_t test_close = closeIgnore,
217
    const send_fd_t send_fd = send_fd_dummy)
Michal Vaner's avatar
Michal Vaner committed
218
219
{
    // Prepare the input feeder and output checker processes
Michal Vaner's avatar
Michal Vaner committed
220
    int input_fd(0), output_fd(0);
Michal Vaner's avatar
Michal Vaner committed
221
222
223
224
225
    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
226
    int result(run(input_fd, output_fd, get_sock_dummy, send_fd, test_close));
Michal Vaner's avatar
Michal Vaner committed
227
228
229
230
    // Close the pipes
    close(input_fd);
    close(output_fd);
    // Did it run well?
Michal Vaner's avatar
Michal Vaner committed
231
    if (should_succeed) {
Michal Vaner's avatar
Michal Vaner committed
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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
        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);
275
    char result[4 + sizeof(int) * 2];
Michal Vaner's avatar
Michal Vaner committed
276
277
278
279
280
281
282
283
284
285
286
287
288
    // 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);
}

289
290
// A close that fails
int
291
closeFail(int) {
292
293
294
295
296
    return (-1);
}

TEST(run, cant_close) {
    run_test("SU4\xff\xff\0\0\0\0", // This has 9 bytes
297
             9, "S\x07", 2, false, closeFail);
298
299
300
}

int
301
sendFDFail(const int, const int) {
302
303
304
305
306
    return (FD_SYSTEM_ERROR);
}

TEST(run, cant_send_fd) {
    run_test("SU4\xff\xff\0\0\0\0", // This has 9 bytes
307
             9, "S", 1, false, closeIgnore, sendFDFail);
308
309
}

Michal Vaner's avatar
Michal Vaner committed
310
}