qemu/tests/unit/test-util-sockets.c
<<
>>
Prefs
   1/*
   2 * Tests for util/qemu-sockets.c
   3 *
   4 * Copyright 2018 Red Hat, Inc.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 *
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "qemu-common.h"
  23#include "qemu/sockets.h"
  24#include "qapi/error.h"
  25#include "socket-helpers.h"
  26#include "monitor/monitor.h"
  27
  28static void test_fd_is_socket_bad(void)
  29{
  30    char *tmp = g_strdup("qemu-test-util-sockets-XXXXXX");
  31    int fd = mkstemp(tmp);
  32    if (fd != 0) {
  33        unlink(tmp);
  34    }
  35    g_free(tmp);
  36
  37    g_assert(fd >= 0);
  38
  39    g_assert(!fd_is_socket(fd));
  40    close(fd);
  41}
  42
  43static void test_fd_is_socket_good(void)
  44{
  45    int fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
  46
  47    g_assert(fd >= 0);
  48
  49    g_assert(fd_is_socket(fd));
  50    close(fd);
  51}
  52
  53static int mon_fd = -1;
  54static const char *mon_fdname;
  55__thread Monitor *cur_mon;
  56
  57int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
  58{
  59    g_assert(cur_mon);
  60    g_assert(mon == cur_mon);
  61    if (mon_fd == -1 || !g_str_equal(mon_fdname, fdname)) {
  62        error_setg(errp, "No fd named %s", fdname);
  63        return -1;
  64    }
  65    return dup(mon_fd);
  66}
  67
  68/*
  69 * Syms of stubs in libqemuutil.a are discarded at .o file
  70 * granularity.  To replace monitor_get_fd() and monitor_cur(), we
  71 * must ensure that we also replace any other symbol that is used in
  72 * the binary and would be taken from the same stub object file,
  73 * otherwise we get duplicate syms at link time.
  74 */
  75Monitor *monitor_cur(void) { return cur_mon; }
  76Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); }
  77int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); }
  78
  79#ifndef _WIN32
  80static void test_socket_fd_pass_name_good(void)
  81{
  82    SocketAddress addr;
  83    int fd;
  84
  85    cur_mon = g_malloc(1); /* Fake a monitor */
  86    mon_fdname = "myfd";
  87    mon_fd = qemu_socket(AF_INET, SOCK_STREAM, 0);
  88    g_assert_cmpint(mon_fd, >, STDERR_FILENO);
  89
  90    addr.type = SOCKET_ADDRESS_TYPE_FD;
  91    addr.u.fd.str = g_strdup(mon_fdname);
  92
  93    fd = socket_connect(&addr, &error_abort);
  94    g_assert_cmpint(fd, !=, -1);
  95    g_assert_cmpint(fd, !=, mon_fd);
  96    close(fd);
  97
  98    fd = socket_listen(&addr, 1, &error_abort);
  99    g_assert_cmpint(fd, !=, -1);
 100    g_assert_cmpint(fd, !=, mon_fd);
 101    close(fd);
 102
 103    g_free(addr.u.fd.str);
 104    mon_fdname = NULL;
 105    close(mon_fd);
 106    mon_fd = -1;
 107    g_free(cur_mon);
 108    cur_mon = NULL;
 109}
 110
 111static void test_socket_fd_pass_name_bad(void)
 112{
 113    SocketAddress addr;
 114    Error *err = NULL;
 115    int fd;
 116
 117    cur_mon = g_malloc(1); /* Fake a monitor */
 118    mon_fdname = "myfd";
 119    mon_fd = dup(STDOUT_FILENO);
 120    g_assert_cmpint(mon_fd, >, STDERR_FILENO);
 121
 122    addr.type = SOCKET_ADDRESS_TYPE_FD;
 123    addr.u.fd.str = g_strdup(mon_fdname);
 124
 125    fd = socket_connect(&addr, &err);
 126    g_assert_cmpint(fd, ==, -1);
 127    error_free_or_abort(&err);
 128
 129    fd = socket_listen(&addr, 1, &err);
 130    g_assert_cmpint(fd, ==, -1);
 131    error_free_or_abort(&err);
 132
 133    g_free(addr.u.fd.str);
 134    mon_fdname = NULL;
 135    close(mon_fd);
 136    mon_fd = -1;
 137    g_free(cur_mon);
 138    cur_mon = NULL;
 139}
 140
 141static void test_socket_fd_pass_name_nomon(void)
 142{
 143    SocketAddress addr;
 144    Error *err = NULL;
 145    int fd;
 146
 147    g_assert(cur_mon == NULL);
 148
 149    addr.type = SOCKET_ADDRESS_TYPE_FD;
 150    addr.u.fd.str = g_strdup("myfd");
 151
 152    fd = socket_connect(&addr, &err);
 153    g_assert_cmpint(fd, ==, -1);
 154    error_free_or_abort(&err);
 155
 156    fd = socket_listen(&addr, 1, &err);
 157    g_assert_cmpint(fd, ==, -1);
 158    error_free_or_abort(&err);
 159
 160    g_free(addr.u.fd.str);
 161}
 162
 163
 164static void test_socket_fd_pass_num_good(void)
 165{
 166    SocketAddress addr;
 167    int fd, sfd;
 168
 169    g_assert(cur_mon == NULL);
 170    sfd = qemu_socket(AF_INET, SOCK_STREAM, 0);
 171    g_assert_cmpint(sfd, >, STDERR_FILENO);
 172
 173    addr.type = SOCKET_ADDRESS_TYPE_FD;
 174    addr.u.fd.str = g_strdup_printf("%d", sfd);
 175
 176    fd = socket_connect(&addr, &error_abort);
 177    g_assert_cmpint(fd, ==, sfd);
 178
 179    fd = socket_listen(&addr, 1, &error_abort);
 180    g_assert_cmpint(fd, ==, sfd);
 181
 182    g_free(addr.u.fd.str);
 183    close(sfd);
 184}
 185
 186static void test_socket_fd_pass_num_bad(void)
 187{
 188    SocketAddress addr;
 189    Error *err = NULL;
 190    int fd, sfd;
 191
 192    g_assert(cur_mon == NULL);
 193    sfd = dup(STDOUT_FILENO);
 194
 195    addr.type = SOCKET_ADDRESS_TYPE_FD;
 196    addr.u.fd.str = g_strdup_printf("%d", sfd);
 197
 198    fd = socket_connect(&addr, &err);
 199    g_assert_cmpint(fd, ==, -1);
 200    error_free_or_abort(&err);
 201
 202    fd = socket_listen(&addr, 1, &err);
 203    g_assert_cmpint(fd, ==, -1);
 204    error_free_or_abort(&err);
 205
 206    g_free(addr.u.fd.str);
 207    close(sfd);
 208}
 209
 210static void test_socket_fd_pass_num_nocli(void)
 211{
 212    SocketAddress addr;
 213    Error *err = NULL;
 214    int fd;
 215
 216    cur_mon = g_malloc(1); /* Fake a monitor */
 217
 218    addr.type = SOCKET_ADDRESS_TYPE_FD;
 219    addr.u.fd.str = g_strdup_printf("%d", STDOUT_FILENO);
 220
 221    fd = socket_connect(&addr, &err);
 222    g_assert_cmpint(fd, ==, -1);
 223    error_free_or_abort(&err);
 224
 225    fd = socket_listen(&addr, 1, &err);
 226    g_assert_cmpint(fd, ==, -1);
 227    error_free_or_abort(&err);
 228
 229    g_free(addr.u.fd.str);
 230}
 231#endif
 232
 233#ifdef CONFIG_LINUX
 234
 235#define ABSTRACT_SOCKET_VARIANTS 3
 236
 237typedef struct {
 238    SocketAddress *server, *client[ABSTRACT_SOCKET_VARIANTS];
 239    bool expect_connect[ABSTRACT_SOCKET_VARIANTS];
 240} abstract_socket_matrix_row;
 241
 242static gpointer unix_client_thread_func(gpointer user_data)
 243{
 244    abstract_socket_matrix_row *row = user_data;
 245    Error *err = NULL;
 246    int i, fd;
 247
 248    for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
 249        if (row->expect_connect[i]) {
 250            fd = socket_connect(row->client[i], &error_abort);
 251            g_assert_cmpint(fd, >=, 0);
 252        } else {
 253            fd = socket_connect(row->client[i], &err);
 254            g_assert_cmpint(fd, ==, -1);
 255            error_free_or_abort(&err);
 256        }
 257        close(fd);
 258    }
 259    return NULL;
 260}
 261
 262static void test_socket_unix_abstract_row(abstract_socket_matrix_row *test)
 263{
 264    int fd, connfd, i;
 265    GThread *cli;
 266    struct sockaddr_un un;
 267    socklen_t len = sizeof(un);
 268
 269    /* Last one must connect, or else accept() below hangs */
 270    assert(test->expect_connect[ABSTRACT_SOCKET_VARIANTS - 1]);
 271
 272    fd = socket_listen(test->server, 1, &error_abort);
 273    g_assert_cmpint(fd, >=, 0);
 274    g_assert(fd_is_socket(fd));
 275
 276    cli = g_thread_new("abstract_unix_client",
 277                       unix_client_thread_func,
 278                       test);
 279
 280    for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
 281        if (test->expect_connect[i]) {
 282            connfd = accept(fd, (struct sockaddr *)&un, &len);
 283            g_assert_cmpint(connfd, !=, -1);
 284            close(connfd);
 285        }
 286    }
 287
 288    close(fd);
 289    g_thread_join(cli);
 290}
 291
 292static void test_socket_unix_abstract(void)
 293{
 294    SocketAddress addr, addr_tight, addr_padded;
 295    abstract_socket_matrix_row matrix[ABSTRACT_SOCKET_VARIANTS] = {
 296        { &addr,
 297          { &addr_tight, &addr_padded, &addr },
 298          { true, false, true } },
 299        { &addr_tight,
 300          { &addr_padded, &addr, &addr_tight },
 301          { false, true, true } },
 302        { &addr_padded,
 303          { &addr, &addr_tight, &addr_padded },
 304          { false, false, true } }
 305    };
 306    int i;
 307
 308    addr.type = SOCKET_ADDRESS_TYPE_UNIX;
 309    addr.u.q_unix.path = g_strdup_printf("unix-%d-%u",
 310                                         getpid(), g_random_int());
 311    addr.u.q_unix.has_abstract = true;
 312    addr.u.q_unix.abstract = true;
 313    addr.u.q_unix.has_tight = false;
 314    addr.u.q_unix.tight = false;
 315
 316    addr_tight = addr;
 317    addr_tight.u.q_unix.has_tight = true;
 318    addr_tight.u.q_unix.tight = true;
 319
 320    addr_padded = addr;
 321    addr_padded.u.q_unix.has_tight = true;
 322    addr_padded.u.q_unix.tight = false;
 323
 324    for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
 325        test_socket_unix_abstract_row(&matrix[i]);
 326    }
 327
 328    g_free(addr.u.q_unix.path);
 329}
 330
 331#endif  /* CONFIG_LINUX */
 332
 333int main(int argc, char **argv)
 334{
 335    bool has_ipv4, has_ipv6;
 336
 337    qemu_init_main_loop(&error_abort);
 338    socket_init();
 339
 340    g_test_init(&argc, &argv, NULL);
 341
 342    /* We're creating actual IPv4/6 sockets, so we should
 343     * check if the host running tests actually supports
 344     * each protocol to avoid breaking tests on machines
 345     * with either IPv4 or IPv6 disabled.
 346     */
 347    if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
 348        g_printerr("socket_check_protocol_support() failed\n");
 349        goto end;
 350    }
 351
 352    if (has_ipv4) {
 353        g_test_add_func("/util/socket/is-socket/bad",
 354                        test_fd_is_socket_bad);
 355        g_test_add_func("/util/socket/is-socket/good",
 356                        test_fd_is_socket_good);
 357#ifndef _WIN32
 358        g_test_add_func("/socket/fd-pass/name/good",
 359                        test_socket_fd_pass_name_good);
 360        g_test_add_func("/socket/fd-pass/name/bad",
 361                        test_socket_fd_pass_name_bad);
 362        g_test_add_func("/socket/fd-pass/name/nomon",
 363                        test_socket_fd_pass_name_nomon);
 364        g_test_add_func("/socket/fd-pass/num/good",
 365                        test_socket_fd_pass_num_good);
 366        g_test_add_func("/socket/fd-pass/num/bad",
 367                        test_socket_fd_pass_num_bad);
 368        g_test_add_func("/socket/fd-pass/num/nocli",
 369                        test_socket_fd_pass_num_nocli);
 370#endif
 371    }
 372
 373#ifdef CONFIG_LINUX
 374    g_test_add_func("/util/socket/unix-abstract",
 375                    test_socket_unix_abstract);
 376#endif
 377
 378end:
 379    return g_test_run();
 380}
 381