1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * vsock test utilities 4 * 5 * Copyright (C) 2017 Red Hat, Inc. 6 * 7 * Author: Stefan Hajnoczi <stefanha@redhat.com> 8 */ 9 10 #include <errno.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <signal.h> 14 #include <unistd.h> 15 16 #include "timeout.h" 17 #include "control.h" 18 #include "util.h" 19 20 /* Install signal handlers */ 21 void init_signals(void) 22 { 23 struct sigaction act = { 24 .sa_handler = sigalrm, 25 }; 26 27 sigaction(SIGALRM, &act, NULL); 28 signal(SIGPIPE, SIG_IGN); 29 } 30 31 /* Parse a CID in string representation */ 32 unsigned int parse_cid(const char *str) 33 { 34 char *endptr = NULL; 35 unsigned long n; 36 37 errno = 0; 38 n = strtoul(str, &endptr, 10); 39 if (errno || *endptr != '\0') { 40 fprintf(stderr, "malformed CID \"%s\"\n", str); 41 exit(EXIT_FAILURE); 42 } 43 return n; 44 } 45 46 /* Connect to <cid, port> and return the file descriptor. */ 47 int vsock_stream_connect(unsigned int cid, unsigned int port) 48 { 49 union { 50 struct sockaddr sa; 51 struct sockaddr_vm svm; 52 } addr = { 53 .svm = { 54 .svm_family = AF_VSOCK, 55 .svm_port = port, 56 .svm_cid = cid, 57 }, 58 }; 59 int ret; 60 int fd; 61 62 control_expectln("LISTENING"); 63 64 fd = socket(AF_VSOCK, SOCK_STREAM, 0); 65 66 timeout_begin(TIMEOUT); 67 do { 68 ret = connect(fd, &addr.sa, sizeof(addr.svm)); 69 timeout_check("connect"); 70 } while (ret < 0 && errno == EINTR); 71 timeout_end(); 72 73 if (ret < 0) { 74 int old_errno = errno; 75 76 close(fd); 77 fd = -1; 78 errno = old_errno; 79 } 80 return fd; 81 } 82 83 /* Listen on <cid, port> and return the first incoming connection. The remote 84 * address is stored to clientaddrp. clientaddrp may be NULL. 85 */ 86 int vsock_stream_accept(unsigned int cid, unsigned int port, 87 struct sockaddr_vm *clientaddrp) 88 { 89 union { 90 struct sockaddr sa; 91 struct sockaddr_vm svm; 92 } addr = { 93 .svm = { 94 .svm_family = AF_VSOCK, 95 .svm_port = port, 96 .svm_cid = cid, 97 }, 98 }; 99 union { 100 struct sockaddr sa; 101 struct sockaddr_vm svm; 102 } clientaddr; 103 socklen_t clientaddr_len = sizeof(clientaddr.svm); 104 int fd; 105 int client_fd; 106 int old_errno; 107 108 fd = socket(AF_VSOCK, SOCK_STREAM, 0); 109 110 if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { 111 perror("bind"); 112 exit(EXIT_FAILURE); 113 } 114 115 if (listen(fd, 1) < 0) { 116 perror("listen"); 117 exit(EXIT_FAILURE); 118 } 119 120 control_writeln("LISTENING"); 121 122 timeout_begin(TIMEOUT); 123 do { 124 client_fd = accept(fd, &clientaddr.sa, &clientaddr_len); 125 timeout_check("accept"); 126 } while (client_fd < 0 && errno == EINTR); 127 timeout_end(); 128 129 old_errno = errno; 130 close(fd); 131 errno = old_errno; 132 133 if (client_fd < 0) 134 return client_fd; 135 136 if (clientaddr_len != sizeof(clientaddr.svm)) { 137 fprintf(stderr, "unexpected addrlen from accept(2), %zu\n", 138 (size_t)clientaddr_len); 139 exit(EXIT_FAILURE); 140 } 141 if (clientaddr.sa.sa_family != AF_VSOCK) { 142 fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n", 143 clientaddr.sa.sa_family); 144 exit(EXIT_FAILURE); 145 } 146 147 if (clientaddrp) 148 *clientaddrp = clientaddr.svm; 149 return client_fd; 150 } 151 152 /* Run test cases. The program terminates if a failure occurs. */ 153 void run_tests(const struct test_case *test_cases, 154 const struct test_opts *opts) 155 { 156 int i; 157 158 for (i = 0; test_cases[i].name; i++) { 159 void (*run)(const struct test_opts *opts); 160 161 printf("%s...", test_cases[i].name); 162 fflush(stdout); 163 164 if (opts->mode == TEST_MODE_CLIENT) { 165 /* Full barrier before executing the next test. This 166 * ensures that client and server are executing the 167 * same test case. In particular, it means whoever is 168 * faster will not see the peer still executing the 169 * last test. This is important because port numbers 170 * can be used by multiple test cases. 171 */ 172 control_expectln("NEXT"); 173 control_writeln("NEXT"); 174 175 run = test_cases[i].run_client; 176 } else { 177 control_writeln("NEXT"); 178 control_expectln("NEXT"); 179 180 run = test_cases[i].run_server; 181 } 182 183 if (run) 184 run(opts); 185 186 printf("ok\n"); 187 } 188 } 189