1df7e0e0dSStefan Hajnoczi // SPDX-License-Identifier: GPL-2.0-only 2df7e0e0dSStefan Hajnoczi /* 3df7e0e0dSStefan Hajnoczi * vsock test utilities 4df7e0e0dSStefan Hajnoczi * 5df7e0e0dSStefan Hajnoczi * Copyright (C) 2017 Red Hat, Inc. 6df7e0e0dSStefan Hajnoczi * 7df7e0e0dSStefan Hajnoczi * Author: Stefan Hajnoczi <stefanha@redhat.com> 8df7e0e0dSStefan Hajnoczi */ 9df7e0e0dSStefan Hajnoczi 10df7e0e0dSStefan Hajnoczi #include <errno.h> 11df7e0e0dSStefan Hajnoczi #include <stdio.h> 12092f32aeSStefan Hajnoczi #include <stdint.h> 13df7e0e0dSStefan Hajnoczi #include <stdlib.h> 14df7e0e0dSStefan Hajnoczi #include <signal.h> 159bb8a29dSStefan Hajnoczi #include <unistd.h> 16df7e0e0dSStefan Hajnoczi 17df7e0e0dSStefan Hajnoczi #include "timeout.h" 189bb8a29dSStefan Hajnoczi #include "control.h" 19df7e0e0dSStefan Hajnoczi #include "util.h" 20df7e0e0dSStefan Hajnoczi 21df7e0e0dSStefan Hajnoczi /* Install signal handlers */ 22df7e0e0dSStefan Hajnoczi void init_signals(void) 23df7e0e0dSStefan Hajnoczi { 24df7e0e0dSStefan Hajnoczi struct sigaction act = { 25df7e0e0dSStefan Hajnoczi .sa_handler = sigalrm, 26df7e0e0dSStefan Hajnoczi }; 27df7e0e0dSStefan Hajnoczi 28df7e0e0dSStefan Hajnoczi sigaction(SIGALRM, &act, NULL); 29df7e0e0dSStefan Hajnoczi signal(SIGPIPE, SIG_IGN); 30df7e0e0dSStefan Hajnoczi } 31df7e0e0dSStefan Hajnoczi 32df7e0e0dSStefan Hajnoczi /* Parse a CID in string representation */ 33df7e0e0dSStefan Hajnoczi unsigned int parse_cid(const char *str) 34df7e0e0dSStefan Hajnoczi { 35df7e0e0dSStefan Hajnoczi char *endptr = NULL; 36df7e0e0dSStefan Hajnoczi unsigned long n; 37df7e0e0dSStefan Hajnoczi 38df7e0e0dSStefan Hajnoczi errno = 0; 39df7e0e0dSStefan Hajnoczi n = strtoul(str, &endptr, 10); 40df7e0e0dSStefan Hajnoczi if (errno || *endptr != '\0') { 41df7e0e0dSStefan Hajnoczi fprintf(stderr, "malformed CID \"%s\"\n", str); 42df7e0e0dSStefan Hajnoczi exit(EXIT_FAILURE); 43df7e0e0dSStefan Hajnoczi } 44df7e0e0dSStefan Hajnoczi return n; 45df7e0e0dSStefan Hajnoczi } 46df7e0e0dSStefan Hajnoczi 479bb8a29dSStefan Hajnoczi /* Connect to <cid, port> and return the file descriptor. */ 489bb8a29dSStefan Hajnoczi int vsock_stream_connect(unsigned int cid, unsigned int port) 499bb8a29dSStefan Hajnoczi { 509bb8a29dSStefan Hajnoczi union { 519bb8a29dSStefan Hajnoczi struct sockaddr sa; 529bb8a29dSStefan Hajnoczi struct sockaddr_vm svm; 539bb8a29dSStefan Hajnoczi } addr = { 549bb8a29dSStefan Hajnoczi .svm = { 559bb8a29dSStefan Hajnoczi .svm_family = AF_VSOCK, 569bb8a29dSStefan Hajnoczi .svm_port = port, 579bb8a29dSStefan Hajnoczi .svm_cid = cid, 589bb8a29dSStefan Hajnoczi }, 599bb8a29dSStefan Hajnoczi }; 609bb8a29dSStefan Hajnoczi int ret; 619bb8a29dSStefan Hajnoczi int fd; 629bb8a29dSStefan Hajnoczi 639bb8a29dSStefan Hajnoczi control_expectln("LISTENING"); 649bb8a29dSStefan Hajnoczi 659bb8a29dSStefan Hajnoczi fd = socket(AF_VSOCK, SOCK_STREAM, 0); 669bb8a29dSStefan Hajnoczi 679bb8a29dSStefan Hajnoczi timeout_begin(TIMEOUT); 689bb8a29dSStefan Hajnoczi do { 699bb8a29dSStefan Hajnoczi ret = connect(fd, &addr.sa, sizeof(addr.svm)); 709bb8a29dSStefan Hajnoczi timeout_check("connect"); 719bb8a29dSStefan Hajnoczi } while (ret < 0 && errno == EINTR); 729bb8a29dSStefan Hajnoczi timeout_end(); 739bb8a29dSStefan Hajnoczi 749bb8a29dSStefan Hajnoczi if (ret < 0) { 759bb8a29dSStefan Hajnoczi int old_errno = errno; 769bb8a29dSStefan Hajnoczi 779bb8a29dSStefan Hajnoczi close(fd); 789bb8a29dSStefan Hajnoczi fd = -1; 799bb8a29dSStefan Hajnoczi errno = old_errno; 809bb8a29dSStefan Hajnoczi } 819bb8a29dSStefan Hajnoczi return fd; 829bb8a29dSStefan Hajnoczi } 839bb8a29dSStefan Hajnoczi 849bb8a29dSStefan Hajnoczi /* Listen on <cid, port> and return the first incoming connection. The remote 859bb8a29dSStefan Hajnoczi * address is stored to clientaddrp. clientaddrp may be NULL. 869bb8a29dSStefan Hajnoczi */ 879bb8a29dSStefan Hajnoczi int vsock_stream_accept(unsigned int cid, unsigned int port, 889bb8a29dSStefan Hajnoczi struct sockaddr_vm *clientaddrp) 899bb8a29dSStefan Hajnoczi { 909bb8a29dSStefan Hajnoczi union { 919bb8a29dSStefan Hajnoczi struct sockaddr sa; 929bb8a29dSStefan Hajnoczi struct sockaddr_vm svm; 939bb8a29dSStefan Hajnoczi } addr = { 949bb8a29dSStefan Hajnoczi .svm = { 959bb8a29dSStefan Hajnoczi .svm_family = AF_VSOCK, 969bb8a29dSStefan Hajnoczi .svm_port = port, 979bb8a29dSStefan Hajnoczi .svm_cid = cid, 989bb8a29dSStefan Hajnoczi }, 999bb8a29dSStefan Hajnoczi }; 1009bb8a29dSStefan Hajnoczi union { 1019bb8a29dSStefan Hajnoczi struct sockaddr sa; 1029bb8a29dSStefan Hajnoczi struct sockaddr_vm svm; 1039bb8a29dSStefan Hajnoczi } clientaddr; 1049bb8a29dSStefan Hajnoczi socklen_t clientaddr_len = sizeof(clientaddr.svm); 1059bb8a29dSStefan Hajnoczi int fd; 1069bb8a29dSStefan Hajnoczi int client_fd; 1079bb8a29dSStefan Hajnoczi int old_errno; 1089bb8a29dSStefan Hajnoczi 1099bb8a29dSStefan Hajnoczi fd = socket(AF_VSOCK, SOCK_STREAM, 0); 1109bb8a29dSStefan Hajnoczi 1119bb8a29dSStefan Hajnoczi if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { 1129bb8a29dSStefan Hajnoczi perror("bind"); 1139bb8a29dSStefan Hajnoczi exit(EXIT_FAILURE); 1149bb8a29dSStefan Hajnoczi } 1159bb8a29dSStefan Hajnoczi 1169bb8a29dSStefan Hajnoczi if (listen(fd, 1) < 0) { 1179bb8a29dSStefan Hajnoczi perror("listen"); 1189bb8a29dSStefan Hajnoczi exit(EXIT_FAILURE); 1199bb8a29dSStefan Hajnoczi } 1209bb8a29dSStefan Hajnoczi 1219bb8a29dSStefan Hajnoczi control_writeln("LISTENING"); 1229bb8a29dSStefan Hajnoczi 1239bb8a29dSStefan Hajnoczi timeout_begin(TIMEOUT); 1249bb8a29dSStefan Hajnoczi do { 1259bb8a29dSStefan Hajnoczi client_fd = accept(fd, &clientaddr.sa, &clientaddr_len); 1269bb8a29dSStefan Hajnoczi timeout_check("accept"); 1279bb8a29dSStefan Hajnoczi } while (client_fd < 0 && errno == EINTR); 1289bb8a29dSStefan Hajnoczi timeout_end(); 1299bb8a29dSStefan Hajnoczi 1309bb8a29dSStefan Hajnoczi old_errno = errno; 1319bb8a29dSStefan Hajnoczi close(fd); 1329bb8a29dSStefan Hajnoczi errno = old_errno; 1339bb8a29dSStefan Hajnoczi 1349bb8a29dSStefan Hajnoczi if (client_fd < 0) 1359bb8a29dSStefan Hajnoczi return client_fd; 1369bb8a29dSStefan Hajnoczi 1379bb8a29dSStefan Hajnoczi if (clientaddr_len != sizeof(clientaddr.svm)) { 1389bb8a29dSStefan Hajnoczi fprintf(stderr, "unexpected addrlen from accept(2), %zu\n", 1399bb8a29dSStefan Hajnoczi (size_t)clientaddr_len); 1409bb8a29dSStefan Hajnoczi exit(EXIT_FAILURE); 1419bb8a29dSStefan Hajnoczi } 1429bb8a29dSStefan Hajnoczi if (clientaddr.sa.sa_family != AF_VSOCK) { 1439bb8a29dSStefan Hajnoczi fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n", 1449bb8a29dSStefan Hajnoczi clientaddr.sa.sa_family); 1459bb8a29dSStefan Hajnoczi exit(EXIT_FAILURE); 1469bb8a29dSStefan Hajnoczi } 1479bb8a29dSStefan Hajnoczi 1489bb8a29dSStefan Hajnoczi if (clientaddrp) 1499bb8a29dSStefan Hajnoczi *clientaddrp = clientaddr.svm; 1509bb8a29dSStefan Hajnoczi return client_fd; 1519bb8a29dSStefan Hajnoczi } 1529bb8a29dSStefan Hajnoczi 153092f32aeSStefan Hajnoczi /* Transmit one byte and check the return value. 154092f32aeSStefan Hajnoczi * 155092f32aeSStefan Hajnoczi * expected_ret: 156092f32aeSStefan Hajnoczi * <0 Negative errno (for testing errors) 157092f32aeSStefan Hajnoczi * 0 End-of-file 158092f32aeSStefan Hajnoczi * 1 Success 159092f32aeSStefan Hajnoczi */ 160092f32aeSStefan Hajnoczi void send_byte(int fd, int expected_ret, int flags) 161092f32aeSStefan Hajnoczi { 162092f32aeSStefan Hajnoczi const uint8_t byte = 'A'; 163092f32aeSStefan Hajnoczi ssize_t nwritten; 164092f32aeSStefan Hajnoczi 165092f32aeSStefan Hajnoczi timeout_begin(TIMEOUT); 166092f32aeSStefan Hajnoczi do { 167092f32aeSStefan Hajnoczi nwritten = send(fd, &byte, sizeof(byte), flags); 168092f32aeSStefan Hajnoczi timeout_check("write"); 169092f32aeSStefan Hajnoczi } while (nwritten < 0 && errno == EINTR); 170092f32aeSStefan Hajnoczi timeout_end(); 171092f32aeSStefan Hajnoczi 172092f32aeSStefan Hajnoczi if (expected_ret < 0) { 173092f32aeSStefan Hajnoczi if (nwritten != -1) { 174092f32aeSStefan Hajnoczi fprintf(stderr, "bogus send(2) return value %zd\n", 175092f32aeSStefan Hajnoczi nwritten); 176092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 177092f32aeSStefan Hajnoczi } 178092f32aeSStefan Hajnoczi if (errno != -expected_ret) { 179092f32aeSStefan Hajnoczi perror("write"); 180092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 181092f32aeSStefan Hajnoczi } 182092f32aeSStefan Hajnoczi return; 183092f32aeSStefan Hajnoczi } 184092f32aeSStefan Hajnoczi 185092f32aeSStefan Hajnoczi if (nwritten < 0) { 186092f32aeSStefan Hajnoczi perror("write"); 187092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 188092f32aeSStefan Hajnoczi } 189092f32aeSStefan Hajnoczi if (nwritten == 0) { 190092f32aeSStefan Hajnoczi if (expected_ret == 0) 191092f32aeSStefan Hajnoczi return; 192092f32aeSStefan Hajnoczi 193092f32aeSStefan Hajnoczi fprintf(stderr, "unexpected EOF while sending byte\n"); 194092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 195092f32aeSStefan Hajnoczi } 196092f32aeSStefan Hajnoczi if (nwritten != sizeof(byte)) { 197092f32aeSStefan Hajnoczi fprintf(stderr, "bogus send(2) return value %zd\n", nwritten); 198092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 199092f32aeSStefan Hajnoczi } 200092f32aeSStefan Hajnoczi } 201092f32aeSStefan Hajnoczi 202092f32aeSStefan Hajnoczi /* Receive one byte and check the return value. 203092f32aeSStefan Hajnoczi * 204092f32aeSStefan Hajnoczi * expected_ret: 205092f32aeSStefan Hajnoczi * <0 Negative errno (for testing errors) 206092f32aeSStefan Hajnoczi * 0 End-of-file 207092f32aeSStefan Hajnoczi * 1 Success 208092f32aeSStefan Hajnoczi */ 209092f32aeSStefan Hajnoczi void recv_byte(int fd, int expected_ret, int flags) 210092f32aeSStefan Hajnoczi { 211092f32aeSStefan Hajnoczi uint8_t byte; 212092f32aeSStefan Hajnoczi ssize_t nread; 213092f32aeSStefan Hajnoczi 214092f32aeSStefan Hajnoczi timeout_begin(TIMEOUT); 215092f32aeSStefan Hajnoczi do { 216092f32aeSStefan Hajnoczi nread = recv(fd, &byte, sizeof(byte), flags); 217092f32aeSStefan Hajnoczi timeout_check("read"); 218092f32aeSStefan Hajnoczi } while (nread < 0 && errno == EINTR); 219092f32aeSStefan Hajnoczi timeout_end(); 220092f32aeSStefan Hajnoczi 221092f32aeSStefan Hajnoczi if (expected_ret < 0) { 222092f32aeSStefan Hajnoczi if (nread != -1) { 223092f32aeSStefan Hajnoczi fprintf(stderr, "bogus recv(2) return value %zd\n", 224092f32aeSStefan Hajnoczi nread); 225092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 226092f32aeSStefan Hajnoczi } 227092f32aeSStefan Hajnoczi if (errno != -expected_ret) { 228092f32aeSStefan Hajnoczi perror("read"); 229092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 230092f32aeSStefan Hajnoczi } 231092f32aeSStefan Hajnoczi return; 232092f32aeSStefan Hajnoczi } 233092f32aeSStefan Hajnoczi 234092f32aeSStefan Hajnoczi if (nread < 0) { 235092f32aeSStefan Hajnoczi perror("read"); 236092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 237092f32aeSStefan Hajnoczi } 238092f32aeSStefan Hajnoczi if (nread == 0) { 239092f32aeSStefan Hajnoczi if (expected_ret == 0) 240092f32aeSStefan Hajnoczi return; 241092f32aeSStefan Hajnoczi 242092f32aeSStefan Hajnoczi fprintf(stderr, "unexpected EOF while receiving byte\n"); 243092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 244092f32aeSStefan Hajnoczi } 245092f32aeSStefan Hajnoczi if (nread != sizeof(byte)) { 246092f32aeSStefan Hajnoczi fprintf(stderr, "bogus recv(2) return value %zd\n", nread); 247092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 248092f32aeSStefan Hajnoczi } 249092f32aeSStefan Hajnoczi if (byte != 'A') { 250092f32aeSStefan Hajnoczi fprintf(stderr, "unexpected byte read %c\n", byte); 251092f32aeSStefan Hajnoczi exit(EXIT_FAILURE); 252092f32aeSStefan Hajnoczi } 253092f32aeSStefan Hajnoczi } 254092f32aeSStefan Hajnoczi 255df7e0e0dSStefan Hajnoczi /* Run test cases. The program terminates if a failure occurs. */ 256df7e0e0dSStefan Hajnoczi void run_tests(const struct test_case *test_cases, 257df7e0e0dSStefan Hajnoczi const struct test_opts *opts) 258df7e0e0dSStefan Hajnoczi { 259df7e0e0dSStefan Hajnoczi int i; 260df7e0e0dSStefan Hajnoczi 261df7e0e0dSStefan Hajnoczi for (i = 0; test_cases[i].name; i++) { 262df7e0e0dSStefan Hajnoczi void (*run)(const struct test_opts *opts); 263df7e0e0dSStefan Hajnoczi 264df7e0e0dSStefan Hajnoczi printf("%s...", test_cases[i].name); 265df7e0e0dSStefan Hajnoczi fflush(stdout); 266df7e0e0dSStefan Hajnoczi 2672f65b44eSStefan Hajnoczi if (opts->mode == TEST_MODE_CLIENT) { 2682f65b44eSStefan Hajnoczi /* Full barrier before executing the next test. This 2692f65b44eSStefan Hajnoczi * ensures that client and server are executing the 2702f65b44eSStefan Hajnoczi * same test case. In particular, it means whoever is 2712f65b44eSStefan Hajnoczi * faster will not see the peer still executing the 2722f65b44eSStefan Hajnoczi * last test. This is important because port numbers 2732f65b44eSStefan Hajnoczi * can be used by multiple test cases. 2742f65b44eSStefan Hajnoczi */ 2752f65b44eSStefan Hajnoczi control_expectln("NEXT"); 2762f65b44eSStefan Hajnoczi control_writeln("NEXT"); 2772f65b44eSStefan Hajnoczi 278df7e0e0dSStefan Hajnoczi run = test_cases[i].run_client; 2792f65b44eSStefan Hajnoczi } else { 2802f65b44eSStefan Hajnoczi control_writeln("NEXT"); 2812f65b44eSStefan Hajnoczi control_expectln("NEXT"); 2822f65b44eSStefan Hajnoczi 283df7e0e0dSStefan Hajnoczi run = test_cases[i].run_server; 2842f65b44eSStefan Hajnoczi } 285df7e0e0dSStefan Hajnoczi 286df7e0e0dSStefan Hajnoczi if (run) 287df7e0e0dSStefan Hajnoczi run(opts); 288df7e0e0dSStefan Hajnoczi 289df7e0e0dSStefan Hajnoczi printf("ok\n"); 290df7e0e0dSStefan Hajnoczi } 291df7e0e0dSStefan Hajnoczi } 292