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 28 static 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 43 static 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 53 static int mon_fd = -1; 54 static const char *mon_fdname; 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 granularity. 69 * To replace monitor_get_fd() we must ensure everything in 70 * stubs/monitor.c is defined, to make sure monitor.o is discarded 71 * otherwise we get duplicate syms at link time. 72 */ 73 __thread Monitor *cur_mon; 74 int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } 75 void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) {} 76 void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp) {} 77 78 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 231 #ifdef __linux__ 232 static gchar *abstract_sock_name; 233 234 static gpointer unix_server_thread_func(gpointer user_data) 235 { 236 SocketAddress addr; 237 Error *err = NULL; 238 int fd = -1; 239 int connfd = -1; 240 struct sockaddr_un un; 241 socklen_t len = sizeof(un); 242 243 addr.type = SOCKET_ADDRESS_TYPE_UNIX; 244 addr.u.q_unix.path = abstract_sock_name; 245 addr.u.q_unix.tight = user_data != NULL; 246 addr.u.q_unix.abstract = true; 247 248 fd = socket_listen(&addr, 1, &err); 249 g_assert_cmpint(fd, >=, 0); 250 g_assert(fd_is_socket(fd)); 251 252 connfd = accept(fd, (struct sockaddr *)&un, &len); 253 g_assert_cmpint(connfd, !=, -1); 254 255 close(fd); 256 257 return NULL; 258 } 259 260 static gpointer unix_client_thread_func(gpointer user_data) 261 { 262 SocketAddress addr; 263 Error *err = NULL; 264 int fd = -1; 265 266 addr.type = SOCKET_ADDRESS_TYPE_UNIX; 267 addr.u.q_unix.path = abstract_sock_name; 268 addr.u.q_unix.tight = user_data != NULL; 269 addr.u.q_unix.abstract = true; 270 271 fd = socket_connect(&addr, &err); 272 273 g_assert_cmpint(fd, >=, 0); 274 275 close(fd); 276 277 return NULL; 278 } 279 280 static void test_socket_unix_abstract_good(void) 281 { 282 GRand *r = g_rand_new(); 283 284 abstract_sock_name = g_strdup_printf("unix-%d-%d", getpid(), 285 g_rand_int_range(r, 100, 1000)); 286 287 /* non tight socklen serv and cli */ 288 GThread *serv = g_thread_new("abstract_unix_server", 289 unix_server_thread_func, 290 NULL); 291 292 sleep(1); 293 294 GThread *cli = g_thread_new("abstract_unix_client", 295 unix_client_thread_func, 296 NULL); 297 298 g_thread_join(cli); 299 g_thread_join(serv); 300 301 /* tight socklen serv and cli */ 302 serv = g_thread_new("abstract_unix_server", 303 unix_server_thread_func, 304 (gpointer)1); 305 306 sleep(1); 307 308 cli = g_thread_new("abstract_unix_client", 309 unix_client_thread_func, 310 (gpointer)1); 311 312 g_thread_join(cli); 313 g_thread_join(serv); 314 315 g_free(abstract_sock_name); 316 g_rand_free(r); 317 } 318 #endif 319 320 int main(int argc, char **argv) 321 { 322 bool has_ipv4, has_ipv6; 323 324 socket_init(); 325 326 g_test_init(&argc, &argv, NULL); 327 328 /* We're creating actual IPv4/6 sockets, so we should 329 * check if the host running tests actually supports 330 * each protocol to avoid breaking tests on machines 331 * with either IPv4 or IPv6 disabled. 332 */ 333 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 334 g_printerr("socket_check_protocol_support() failed\n"); 335 goto end; 336 } 337 338 if (has_ipv4) { 339 g_test_add_func("/util/socket/is-socket/bad", 340 test_fd_is_socket_bad); 341 g_test_add_func("/util/socket/is-socket/good", 342 test_fd_is_socket_good); 343 g_test_add_func("/socket/fd-pass/name/good", 344 test_socket_fd_pass_name_good); 345 g_test_add_func("/socket/fd-pass/name/bad", 346 test_socket_fd_pass_name_bad); 347 g_test_add_func("/socket/fd-pass/name/nomon", 348 test_socket_fd_pass_name_nomon); 349 g_test_add_func("/socket/fd-pass/num/good", 350 test_socket_fd_pass_num_good); 351 g_test_add_func("/socket/fd-pass/num/bad", 352 test_socket_fd_pass_num_bad); 353 g_test_add_func("/socket/fd-pass/num/nocli", 354 test_socket_fd_pass_num_nocli); 355 } 356 357 #ifdef __linux__ 358 g_test_add_func("/util/socket/unix-abstract/good", 359 test_socket_unix_abstract_good); 360 #endif 361 362 end: 363 return g_test_run(); 364 } 365