qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

test-util-sockets.c (9988B)


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