1cdbcc18dSStefan Hajnoczi // SPDX-License-Identifier: GPL-2.0-only 2cdbcc18dSStefan Hajnoczi /* 3cdbcc18dSStefan Hajnoczi * vsock_test - vsock.ko test suite 4cdbcc18dSStefan Hajnoczi * 5cdbcc18dSStefan Hajnoczi * Copyright (C) 2017 Red Hat, Inc. 6cdbcc18dSStefan Hajnoczi * 7cdbcc18dSStefan Hajnoczi * Author: Stefan Hajnoczi <stefanha@redhat.com> 8cdbcc18dSStefan Hajnoczi */ 9cdbcc18dSStefan Hajnoczi 10cdbcc18dSStefan Hajnoczi #include <getopt.h> 11cdbcc18dSStefan Hajnoczi #include <stdio.h> 12cdbcc18dSStefan Hajnoczi #include <stdlib.h> 13cdbcc18dSStefan Hajnoczi #include <string.h> 14cdbcc18dSStefan Hajnoczi #include <errno.h> 15cdbcc18dSStefan Hajnoczi #include <unistd.h> 165a2b2425SStefano Garzarella #include <linux/kernel.h> 1741b792d7SArseny Krasnov #include <sys/types.h> 1841b792d7SArseny Krasnov #include <sys/socket.h> 19efb3719fSKrasnov Arseniy Vladimirovich #include <time.h> 20e89600ebSKrasnov Arseniy Vladimirovich #include <sys/mman.h> 21b1346338SArseniy Krasnov #include <poll.h> 22cdbcc18dSStefan Hajnoczi 23cdbcc18dSStefan Hajnoczi #include "timeout.h" 24cdbcc18dSStefan Hajnoczi #include "control.h" 25cdbcc18dSStefan Hajnoczi #include "util.h" 26cdbcc18dSStefan Hajnoczi 27cdbcc18dSStefan Hajnoczi static void test_stream_connection_reset(const struct test_opts *opts) 28cdbcc18dSStefan Hajnoczi { 29cdbcc18dSStefan Hajnoczi union { 30cdbcc18dSStefan Hajnoczi struct sockaddr sa; 31cdbcc18dSStefan Hajnoczi struct sockaddr_vm svm; 32cdbcc18dSStefan Hajnoczi } addr = { 33cdbcc18dSStefan Hajnoczi .svm = { 34cdbcc18dSStefan Hajnoczi .svm_family = AF_VSOCK, 35cdbcc18dSStefan Hajnoczi .svm_port = 1234, 36cdbcc18dSStefan Hajnoczi .svm_cid = opts->peer_cid, 37cdbcc18dSStefan Hajnoczi }, 38cdbcc18dSStefan Hajnoczi }; 39cdbcc18dSStefan Hajnoczi int ret; 40cdbcc18dSStefan Hajnoczi int fd; 41cdbcc18dSStefan Hajnoczi 42cdbcc18dSStefan Hajnoczi fd = socket(AF_VSOCK, SOCK_STREAM, 0); 43cdbcc18dSStefan Hajnoczi 44cdbcc18dSStefan Hajnoczi timeout_begin(TIMEOUT); 45cdbcc18dSStefan Hajnoczi do { 46cdbcc18dSStefan Hajnoczi ret = connect(fd, &addr.sa, sizeof(addr.svm)); 47cdbcc18dSStefan Hajnoczi timeout_check("connect"); 48cdbcc18dSStefan Hajnoczi } while (ret < 0 && errno == EINTR); 49cdbcc18dSStefan Hajnoczi timeout_end(); 50cdbcc18dSStefan Hajnoczi 51cdbcc18dSStefan Hajnoczi if (ret != -1) { 52cdbcc18dSStefan Hajnoczi fprintf(stderr, "expected connect(2) failure, got %d\n", ret); 53cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 54cdbcc18dSStefan Hajnoczi } 55cdbcc18dSStefan Hajnoczi if (errno != ECONNRESET) { 56cdbcc18dSStefan Hajnoczi fprintf(stderr, "unexpected connect(2) errno %d\n", errno); 57cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 58cdbcc18dSStefan Hajnoczi } 59cdbcc18dSStefan Hajnoczi 60cdbcc18dSStefan Hajnoczi close(fd); 61cdbcc18dSStefan Hajnoczi } 62cdbcc18dSStefan Hajnoczi 639de9f7d1SSebastien Boeuf static void test_stream_bind_only_client(const struct test_opts *opts) 649de9f7d1SSebastien Boeuf { 659de9f7d1SSebastien Boeuf union { 669de9f7d1SSebastien Boeuf struct sockaddr sa; 679de9f7d1SSebastien Boeuf struct sockaddr_vm svm; 689de9f7d1SSebastien Boeuf } addr = { 699de9f7d1SSebastien Boeuf .svm = { 709de9f7d1SSebastien Boeuf .svm_family = AF_VSOCK, 719de9f7d1SSebastien Boeuf .svm_port = 1234, 729de9f7d1SSebastien Boeuf .svm_cid = opts->peer_cid, 739de9f7d1SSebastien Boeuf }, 749de9f7d1SSebastien Boeuf }; 759de9f7d1SSebastien Boeuf int ret; 769de9f7d1SSebastien Boeuf int fd; 779de9f7d1SSebastien Boeuf 789de9f7d1SSebastien Boeuf /* Wait for the server to be ready */ 799de9f7d1SSebastien Boeuf control_expectln("BIND"); 809de9f7d1SSebastien Boeuf 819de9f7d1SSebastien Boeuf fd = socket(AF_VSOCK, SOCK_STREAM, 0); 829de9f7d1SSebastien Boeuf 839de9f7d1SSebastien Boeuf timeout_begin(TIMEOUT); 849de9f7d1SSebastien Boeuf do { 859de9f7d1SSebastien Boeuf ret = connect(fd, &addr.sa, sizeof(addr.svm)); 869de9f7d1SSebastien Boeuf timeout_check("connect"); 879de9f7d1SSebastien Boeuf } while (ret < 0 && errno == EINTR); 889de9f7d1SSebastien Boeuf timeout_end(); 899de9f7d1SSebastien Boeuf 909de9f7d1SSebastien Boeuf if (ret != -1) { 919de9f7d1SSebastien Boeuf fprintf(stderr, "expected connect(2) failure, got %d\n", ret); 929de9f7d1SSebastien Boeuf exit(EXIT_FAILURE); 939de9f7d1SSebastien Boeuf } 949de9f7d1SSebastien Boeuf if (errno != ECONNRESET) { 959de9f7d1SSebastien Boeuf fprintf(stderr, "unexpected connect(2) errno %d\n", errno); 969de9f7d1SSebastien Boeuf exit(EXIT_FAILURE); 979de9f7d1SSebastien Boeuf } 989de9f7d1SSebastien Boeuf 999de9f7d1SSebastien Boeuf /* Notify the server that the client has finished */ 1009de9f7d1SSebastien Boeuf control_writeln("DONE"); 1019de9f7d1SSebastien Boeuf 1029de9f7d1SSebastien Boeuf close(fd); 1039de9f7d1SSebastien Boeuf } 1049de9f7d1SSebastien Boeuf 1059de9f7d1SSebastien Boeuf static void test_stream_bind_only_server(const struct test_opts *opts) 1069de9f7d1SSebastien Boeuf { 1079de9f7d1SSebastien Boeuf union { 1089de9f7d1SSebastien Boeuf struct sockaddr sa; 1099de9f7d1SSebastien Boeuf struct sockaddr_vm svm; 1109de9f7d1SSebastien Boeuf } addr = { 1119de9f7d1SSebastien Boeuf .svm = { 1129de9f7d1SSebastien Boeuf .svm_family = AF_VSOCK, 1139de9f7d1SSebastien Boeuf .svm_port = 1234, 1149de9f7d1SSebastien Boeuf .svm_cid = VMADDR_CID_ANY, 1159de9f7d1SSebastien Boeuf }, 1169de9f7d1SSebastien Boeuf }; 1179de9f7d1SSebastien Boeuf int fd; 1189de9f7d1SSebastien Boeuf 1199de9f7d1SSebastien Boeuf fd = socket(AF_VSOCK, SOCK_STREAM, 0); 1209de9f7d1SSebastien Boeuf 1219de9f7d1SSebastien Boeuf if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { 1229de9f7d1SSebastien Boeuf perror("bind"); 1239de9f7d1SSebastien Boeuf exit(EXIT_FAILURE); 1249de9f7d1SSebastien Boeuf } 1259de9f7d1SSebastien Boeuf 1269de9f7d1SSebastien Boeuf /* Notify the client that the server is ready */ 1279de9f7d1SSebastien Boeuf control_writeln("BIND"); 1289de9f7d1SSebastien Boeuf 1299de9f7d1SSebastien Boeuf /* Wait for the client to finish */ 1309de9f7d1SSebastien Boeuf control_expectln("DONE"); 1319de9f7d1SSebastien Boeuf 1329de9f7d1SSebastien Boeuf close(fd); 1339de9f7d1SSebastien Boeuf } 1349de9f7d1SSebastien Boeuf 135cdbcc18dSStefan Hajnoczi static void test_stream_client_close_client(const struct test_opts *opts) 136cdbcc18dSStefan Hajnoczi { 137cdbcc18dSStefan Hajnoczi int fd; 138cdbcc18dSStefan Hajnoczi 139cdbcc18dSStefan Hajnoczi fd = vsock_stream_connect(opts->peer_cid, 1234); 140cdbcc18dSStefan Hajnoczi if (fd < 0) { 141cdbcc18dSStefan Hajnoczi perror("connect"); 142cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 143cdbcc18dSStefan Hajnoczi } 144cdbcc18dSStefan Hajnoczi 145cdbcc18dSStefan Hajnoczi send_byte(fd, 1, 0); 146cdbcc18dSStefan Hajnoczi close(fd); 147cdbcc18dSStefan Hajnoczi } 148cdbcc18dSStefan Hajnoczi 149cdbcc18dSStefan Hajnoczi static void test_stream_client_close_server(const struct test_opts *opts) 150cdbcc18dSStefan Hajnoczi { 151cdbcc18dSStefan Hajnoczi int fd; 152cdbcc18dSStefan Hajnoczi 153cdbcc18dSStefan Hajnoczi fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 154cdbcc18dSStefan Hajnoczi if (fd < 0) { 155cdbcc18dSStefan Hajnoczi perror("accept"); 156cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 157cdbcc18dSStefan Hajnoczi } 158cdbcc18dSStefan Hajnoczi 159770ce007SStefano Garzarella /* Wait for the remote to close the connection, before check 160770ce007SStefano Garzarella * -EPIPE error on send. 161770ce007SStefano Garzarella */ 162770ce007SStefano Garzarella vsock_wait_remote_close(fd); 163cdbcc18dSStefan Hajnoczi 164cdbcc18dSStefan Hajnoczi send_byte(fd, -EPIPE, 0); 165cdbcc18dSStefan Hajnoczi recv_byte(fd, 1, 0); 166cdbcc18dSStefan Hajnoczi recv_byte(fd, 0, 0); 167cdbcc18dSStefan Hajnoczi close(fd); 168cdbcc18dSStefan Hajnoczi } 169cdbcc18dSStefan Hajnoczi 170cdbcc18dSStefan Hajnoczi static void test_stream_server_close_client(const struct test_opts *opts) 171cdbcc18dSStefan Hajnoczi { 172cdbcc18dSStefan Hajnoczi int fd; 173cdbcc18dSStefan Hajnoczi 174cdbcc18dSStefan Hajnoczi fd = vsock_stream_connect(opts->peer_cid, 1234); 175cdbcc18dSStefan Hajnoczi if (fd < 0) { 176cdbcc18dSStefan Hajnoczi perror("connect"); 177cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 178cdbcc18dSStefan Hajnoczi } 179cdbcc18dSStefan Hajnoczi 180770ce007SStefano Garzarella /* Wait for the remote to close the connection, before check 181770ce007SStefano Garzarella * -EPIPE error on send. 182770ce007SStefano Garzarella */ 183770ce007SStefano Garzarella vsock_wait_remote_close(fd); 184cdbcc18dSStefan Hajnoczi 185cdbcc18dSStefan Hajnoczi send_byte(fd, -EPIPE, 0); 186cdbcc18dSStefan Hajnoczi recv_byte(fd, 1, 0); 187cdbcc18dSStefan Hajnoczi recv_byte(fd, 0, 0); 188cdbcc18dSStefan Hajnoczi close(fd); 189cdbcc18dSStefan Hajnoczi } 190cdbcc18dSStefan Hajnoczi 191cdbcc18dSStefan Hajnoczi static void test_stream_server_close_server(const struct test_opts *opts) 192cdbcc18dSStefan Hajnoczi { 193cdbcc18dSStefan Hajnoczi int fd; 194cdbcc18dSStefan Hajnoczi 195cdbcc18dSStefan Hajnoczi fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 196cdbcc18dSStefan Hajnoczi if (fd < 0) { 197cdbcc18dSStefan Hajnoczi perror("accept"); 198cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 199cdbcc18dSStefan Hajnoczi } 200cdbcc18dSStefan Hajnoczi 201cdbcc18dSStefan Hajnoczi send_byte(fd, 1, 0); 202cdbcc18dSStefan Hajnoczi close(fd); 203cdbcc18dSStefan Hajnoczi } 204cdbcc18dSStefan Hajnoczi 205cdbcc18dSStefan Hajnoczi /* With the standard socket sizes, VMCI is able to support about 100 206cdbcc18dSStefan Hajnoczi * concurrent stream connections. 207cdbcc18dSStefan Hajnoczi */ 208cdbcc18dSStefan Hajnoczi #define MULTICONN_NFDS 100 209cdbcc18dSStefan Hajnoczi 210cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_client(const struct test_opts *opts) 211cdbcc18dSStefan Hajnoczi { 212cdbcc18dSStefan Hajnoczi int fds[MULTICONN_NFDS]; 213cdbcc18dSStefan Hajnoczi int i; 214cdbcc18dSStefan Hajnoczi 215cdbcc18dSStefan Hajnoczi for (i = 0; i < MULTICONN_NFDS; i++) { 216cdbcc18dSStefan Hajnoczi fds[i] = vsock_stream_connect(opts->peer_cid, 1234); 217cdbcc18dSStefan Hajnoczi if (fds[i] < 0) { 218cdbcc18dSStefan Hajnoczi perror("connect"); 219cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 220cdbcc18dSStefan Hajnoczi } 221cdbcc18dSStefan Hajnoczi } 222cdbcc18dSStefan Hajnoczi 223cdbcc18dSStefan Hajnoczi for (i = 0; i < MULTICONN_NFDS; i++) { 224cdbcc18dSStefan Hajnoczi if (i % 2) 225cdbcc18dSStefan Hajnoczi recv_byte(fds[i], 1, 0); 226cdbcc18dSStefan Hajnoczi else 227cdbcc18dSStefan Hajnoczi send_byte(fds[i], 1, 0); 228cdbcc18dSStefan Hajnoczi } 229cdbcc18dSStefan Hajnoczi 230cdbcc18dSStefan Hajnoczi for (i = 0; i < MULTICONN_NFDS; i++) 231cdbcc18dSStefan Hajnoczi close(fds[i]); 232cdbcc18dSStefan Hajnoczi } 233cdbcc18dSStefan Hajnoczi 234cdbcc18dSStefan Hajnoczi static void test_stream_multiconn_server(const struct test_opts *opts) 235cdbcc18dSStefan Hajnoczi { 236cdbcc18dSStefan Hajnoczi int fds[MULTICONN_NFDS]; 237cdbcc18dSStefan Hajnoczi int i; 238cdbcc18dSStefan Hajnoczi 239cdbcc18dSStefan Hajnoczi for (i = 0; i < MULTICONN_NFDS; i++) { 240cdbcc18dSStefan Hajnoczi fds[i] = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 241cdbcc18dSStefan Hajnoczi if (fds[i] < 0) { 242cdbcc18dSStefan Hajnoczi perror("accept"); 243cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 244cdbcc18dSStefan Hajnoczi } 245cdbcc18dSStefan Hajnoczi } 246cdbcc18dSStefan Hajnoczi 247cdbcc18dSStefan Hajnoczi for (i = 0; i < MULTICONN_NFDS; i++) { 248cdbcc18dSStefan Hajnoczi if (i % 2) 249cdbcc18dSStefan Hajnoczi send_byte(fds[i], 1, 0); 250cdbcc18dSStefan Hajnoczi else 251cdbcc18dSStefan Hajnoczi recv_byte(fds[i], 1, 0); 252cdbcc18dSStefan Hajnoczi } 253cdbcc18dSStefan Hajnoczi 254cdbcc18dSStefan Hajnoczi for (i = 0; i < MULTICONN_NFDS; i++) 255cdbcc18dSStefan Hajnoczi close(fds[i]); 256cdbcc18dSStefan Hajnoczi } 257cdbcc18dSStefan Hajnoczi 258d6269a93SStefano Garzarella static void test_stream_msg_peek_client(const struct test_opts *opts) 259d6269a93SStefano Garzarella { 260d6269a93SStefano Garzarella int fd; 261d6269a93SStefano Garzarella 262d6269a93SStefano Garzarella fd = vsock_stream_connect(opts->peer_cid, 1234); 263d6269a93SStefano Garzarella if (fd < 0) { 264d6269a93SStefano Garzarella perror("connect"); 265d6269a93SStefano Garzarella exit(EXIT_FAILURE); 266d6269a93SStefano Garzarella } 267d6269a93SStefano Garzarella 268d6269a93SStefano Garzarella send_byte(fd, 1, 0); 269d6269a93SStefano Garzarella close(fd); 270d6269a93SStefano Garzarella } 271d6269a93SStefano Garzarella 272d6269a93SStefano Garzarella static void test_stream_msg_peek_server(const struct test_opts *opts) 273d6269a93SStefano Garzarella { 274d6269a93SStefano Garzarella int fd; 275d6269a93SStefano Garzarella 276d6269a93SStefano Garzarella fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 277d6269a93SStefano Garzarella if (fd < 0) { 278d6269a93SStefano Garzarella perror("accept"); 279d6269a93SStefano Garzarella exit(EXIT_FAILURE); 280d6269a93SStefano Garzarella } 281d6269a93SStefano Garzarella 282d6269a93SStefano Garzarella recv_byte(fd, 1, MSG_PEEK); 283d6269a93SStefano Garzarella recv_byte(fd, 1, 0); 284d6269a93SStefano Garzarella close(fd); 285d6269a93SStefano Garzarella } 286d6269a93SStefano Garzarella 2875c338112SArseniy Krasnov #define SOCK_BUF_SIZE (2 * 1024 * 1024) 2885c338112SArseniy Krasnov #define MAX_MSG_SIZE (32 * 1024) 2895c338112SArseniy Krasnov 29041b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) 29141b792d7SArseny Krasnov { 2925c338112SArseniy Krasnov unsigned long curr_hash; 2935c338112SArseniy Krasnov int page_size; 2945c338112SArseniy Krasnov int msg_count; 29541b792d7SArseny Krasnov int fd; 29641b792d7SArseny Krasnov 29741b792d7SArseny Krasnov fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 29841b792d7SArseny Krasnov if (fd < 0) { 29941b792d7SArseny Krasnov perror("connect"); 30041b792d7SArseny Krasnov exit(EXIT_FAILURE); 30141b792d7SArseny Krasnov } 30241b792d7SArseny Krasnov 3035c338112SArseniy Krasnov /* Wait, until receiver sets buffer size. */ 3045c338112SArseniy Krasnov control_expectln("SRVREADY"); 3055c338112SArseniy Krasnov 3065c338112SArseniy Krasnov curr_hash = 0; 3075c338112SArseniy Krasnov page_size = getpagesize(); 3085c338112SArseniy Krasnov msg_count = SOCK_BUF_SIZE / MAX_MSG_SIZE; 3095c338112SArseniy Krasnov 3105c338112SArseniy Krasnov for (int i = 0; i < msg_count; i++) { 3115c338112SArseniy Krasnov ssize_t send_size; 3125c338112SArseniy Krasnov size_t buf_size; 3135c338112SArseniy Krasnov int flags; 3145c338112SArseniy Krasnov void *buf; 3155c338112SArseniy Krasnov 3165c338112SArseniy Krasnov /* Use "small" buffers and "big" buffers. */ 3175c338112SArseniy Krasnov if (i & 1) 3185c338112SArseniy Krasnov buf_size = page_size + 3195c338112SArseniy Krasnov (rand() % (MAX_MSG_SIZE - page_size)); 3205c338112SArseniy Krasnov else 3215c338112SArseniy Krasnov buf_size = 1 + (rand() % page_size); 3225c338112SArseniy Krasnov 3235c338112SArseniy Krasnov buf = malloc(buf_size); 3245c338112SArseniy Krasnov 3255c338112SArseniy Krasnov if (!buf) { 3265c338112SArseniy Krasnov perror("malloc"); 3275c338112SArseniy Krasnov exit(EXIT_FAILURE); 3285c338112SArseniy Krasnov } 3295c338112SArseniy Krasnov 3305c338112SArseniy Krasnov memset(buf, rand() & 0xff, buf_size); 3315c338112SArseniy Krasnov /* Set at least one MSG_EOR + some random. */ 3325c338112SArseniy Krasnov if (i == (msg_count / 2) || (rand() & 1)) { 3335c338112SArseniy Krasnov flags = MSG_EOR; 3345c338112SArseniy Krasnov curr_hash++; 3355c338112SArseniy Krasnov } else { 3365c338112SArseniy Krasnov flags = 0; 3375c338112SArseniy Krasnov } 3385c338112SArseniy Krasnov 3395c338112SArseniy Krasnov send_size = send(fd, buf, buf_size, flags); 3405c338112SArseniy Krasnov 3415c338112SArseniy Krasnov if (send_size < 0) { 3425c338112SArseniy Krasnov perror("send"); 3435c338112SArseniy Krasnov exit(EXIT_FAILURE); 3445c338112SArseniy Krasnov } 3455c338112SArseniy Krasnov 3465c338112SArseniy Krasnov if (send_size != buf_size) { 3475c338112SArseniy Krasnov fprintf(stderr, "Invalid send size\n"); 3485c338112SArseniy Krasnov exit(EXIT_FAILURE); 3495c338112SArseniy Krasnov } 3505c338112SArseniy Krasnov 3515c338112SArseniy Krasnov /* 3525c338112SArseniy Krasnov * Hash sum is computed at both client and server in 3535c338112SArseniy Krasnov * the same way: 3545c338112SArseniy Krasnov * H += hash('message data') 3555c338112SArseniy Krasnov * Such hash "controls" both data integrity and message 3565c338112SArseniy Krasnov * bounds. After data exchange, both sums are compared 3575c338112SArseniy Krasnov * using control socket, and if message bounds wasn't 3585c338112SArseniy Krasnov * broken - two values must be equal. 3595c338112SArseniy Krasnov */ 3605c338112SArseniy Krasnov curr_hash += hash_djb2(buf, buf_size); 3615c338112SArseniy Krasnov free(buf); 3625c338112SArseniy Krasnov } 36341b792d7SArseny Krasnov 36441b792d7SArseny Krasnov control_writeln("SENDDONE"); 3655c338112SArseniy Krasnov control_writeulong(curr_hash); 36641b792d7SArseny Krasnov close(fd); 36741b792d7SArseny Krasnov } 36841b792d7SArseny Krasnov 36941b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) 37041b792d7SArseny Krasnov { 3715c338112SArseniy Krasnov unsigned long sock_buf_size; 3725c338112SArseniy Krasnov unsigned long remote_hash; 3735c338112SArseniy Krasnov unsigned long curr_hash; 37441b792d7SArseny Krasnov int fd; 3755c338112SArseniy Krasnov char buf[MAX_MSG_SIZE]; 37641b792d7SArseny Krasnov struct msghdr msg = {0}; 37741b792d7SArseny Krasnov struct iovec iov = {0}; 37841b792d7SArseny Krasnov 37941b792d7SArseny Krasnov fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 38041b792d7SArseny Krasnov if (fd < 0) { 38141b792d7SArseny Krasnov perror("accept"); 38241b792d7SArseny Krasnov exit(EXIT_FAILURE); 38341b792d7SArseny Krasnov } 38441b792d7SArseny Krasnov 3855c338112SArseniy Krasnov sock_buf_size = SOCK_BUF_SIZE; 3865c338112SArseniy Krasnov 3875c338112SArseniy Krasnov if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, 3885c338112SArseniy Krasnov &sock_buf_size, sizeof(sock_buf_size))) { 3895c338112SArseniy Krasnov perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)"); 3905c338112SArseniy Krasnov exit(EXIT_FAILURE); 3915c338112SArseniy Krasnov } 3925c338112SArseniy Krasnov 3935c338112SArseniy Krasnov if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, 3945c338112SArseniy Krasnov &sock_buf_size, sizeof(sock_buf_size))) { 3955c338112SArseniy Krasnov perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)"); 3965c338112SArseniy Krasnov exit(EXIT_FAILURE); 3975c338112SArseniy Krasnov } 3985c338112SArseniy Krasnov 3995c338112SArseniy Krasnov /* Ready to receive data. */ 4005c338112SArseniy Krasnov control_writeln("SRVREADY"); 4015c338112SArseniy Krasnov /* Wait, until peer sends whole data. */ 40241b792d7SArseny Krasnov control_expectln("SENDDONE"); 40341b792d7SArseny Krasnov iov.iov_base = buf; 40441b792d7SArseny Krasnov iov.iov_len = sizeof(buf); 40541b792d7SArseny Krasnov msg.msg_iov = &iov; 40641b792d7SArseny Krasnov msg.msg_iovlen = 1; 40741b792d7SArseny Krasnov 4085c338112SArseniy Krasnov curr_hash = 0; 4095c338112SArseniy Krasnov 4105c338112SArseniy Krasnov while (1) { 4115c338112SArseniy Krasnov ssize_t recv_size; 4125c338112SArseniy Krasnov 4135c338112SArseniy Krasnov recv_size = recvmsg(fd, &msg, 0); 4145c338112SArseniy Krasnov 4155c338112SArseniy Krasnov if (!recv_size) 4165c338112SArseniy Krasnov break; 4175c338112SArseniy Krasnov 4185c338112SArseniy Krasnov if (recv_size < 0) { 4195c338112SArseniy Krasnov perror("recvmsg"); 42041b792d7SArseny Krasnov exit(EXIT_FAILURE); 42141b792d7SArseny Krasnov } 4220e115c45SArseny Krasnov 4235c338112SArseniy Krasnov if (msg.msg_flags & MSG_EOR) 4245c338112SArseniy Krasnov curr_hash++; 4255c338112SArseniy Krasnov 4265c338112SArseniy Krasnov curr_hash += hash_djb2(msg.msg_iov[0].iov_base, recv_size); 42741b792d7SArseny Krasnov } 42841b792d7SArseny Krasnov 42941b792d7SArseny Krasnov close(fd); 4305c338112SArseniy Krasnov remote_hash = control_readulong(); 4315c338112SArseniy Krasnov 4325c338112SArseniy Krasnov if (curr_hash != remote_hash) { 4335c338112SArseniy Krasnov fprintf(stderr, "Message bounds broken\n"); 4345c338112SArseniy Krasnov exit(EXIT_FAILURE); 4355c338112SArseniy Krasnov } 43641b792d7SArseny Krasnov } 43741b792d7SArseny Krasnov 43841b792d7SArseny Krasnov #define MESSAGE_TRUNC_SZ 32 43941b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_client(const struct test_opts *opts) 44041b792d7SArseny Krasnov { 44141b792d7SArseny Krasnov int fd; 44241b792d7SArseny Krasnov char buf[MESSAGE_TRUNC_SZ]; 44341b792d7SArseny Krasnov 44441b792d7SArseny Krasnov fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 44541b792d7SArseny Krasnov if (fd < 0) { 44641b792d7SArseny Krasnov perror("connect"); 44741b792d7SArseny Krasnov exit(EXIT_FAILURE); 44841b792d7SArseny Krasnov } 44941b792d7SArseny Krasnov 45041b792d7SArseny Krasnov if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) { 45141b792d7SArseny Krasnov perror("send failed"); 45241b792d7SArseny Krasnov exit(EXIT_FAILURE); 45341b792d7SArseny Krasnov } 45441b792d7SArseny Krasnov 45541b792d7SArseny Krasnov control_writeln("SENDDONE"); 45641b792d7SArseny Krasnov close(fd); 45741b792d7SArseny Krasnov } 45841b792d7SArseny Krasnov 45941b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_server(const struct test_opts *opts) 46041b792d7SArseny Krasnov { 46141b792d7SArseny Krasnov int fd; 46241b792d7SArseny Krasnov char buf[MESSAGE_TRUNC_SZ / 2]; 46341b792d7SArseny Krasnov struct msghdr msg = {0}; 46441b792d7SArseny Krasnov struct iovec iov = {0}; 46541b792d7SArseny Krasnov 46641b792d7SArseny Krasnov fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 46741b792d7SArseny Krasnov if (fd < 0) { 46841b792d7SArseny Krasnov perror("accept"); 46941b792d7SArseny Krasnov exit(EXIT_FAILURE); 47041b792d7SArseny Krasnov } 47141b792d7SArseny Krasnov 47241b792d7SArseny Krasnov control_expectln("SENDDONE"); 47341b792d7SArseny Krasnov iov.iov_base = buf; 47441b792d7SArseny Krasnov iov.iov_len = sizeof(buf); 47541b792d7SArseny Krasnov msg.msg_iov = &iov; 47641b792d7SArseny Krasnov msg.msg_iovlen = 1; 47741b792d7SArseny Krasnov 47841b792d7SArseny Krasnov ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC); 47941b792d7SArseny Krasnov 48041b792d7SArseny Krasnov if (ret != MESSAGE_TRUNC_SZ) { 48141b792d7SArseny Krasnov printf("%zi\n", ret); 48241b792d7SArseny Krasnov perror("MSG_TRUNC doesn't work"); 48341b792d7SArseny Krasnov exit(EXIT_FAILURE); 48441b792d7SArseny Krasnov } 48541b792d7SArseny Krasnov 48641b792d7SArseny Krasnov if (!(msg.msg_flags & MSG_TRUNC)) { 48741b792d7SArseny Krasnov fprintf(stderr, "MSG_TRUNC expected\n"); 48841b792d7SArseny Krasnov exit(EXIT_FAILURE); 48941b792d7SArseny Krasnov } 49041b792d7SArseny Krasnov 49141b792d7SArseny Krasnov close(fd); 49241b792d7SArseny Krasnov } 49341b792d7SArseny Krasnov 494efb3719fSKrasnov Arseniy Vladimirovich static time_t current_nsec(void) 495efb3719fSKrasnov Arseniy Vladimirovich { 496efb3719fSKrasnov Arseniy Vladimirovich struct timespec ts; 497efb3719fSKrasnov Arseniy Vladimirovich 498efb3719fSKrasnov Arseniy Vladimirovich if (clock_gettime(CLOCK_REALTIME, &ts)) { 499efb3719fSKrasnov Arseniy Vladimirovich perror("clock_gettime(3) failed"); 500efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 501efb3719fSKrasnov Arseniy Vladimirovich } 502efb3719fSKrasnov Arseniy Vladimirovich 503efb3719fSKrasnov Arseniy Vladimirovich return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec; 504efb3719fSKrasnov Arseniy Vladimirovich } 505efb3719fSKrasnov Arseniy Vladimirovich 506efb3719fSKrasnov Arseniy Vladimirovich #define RCVTIMEO_TIMEOUT_SEC 1 507efb3719fSKrasnov Arseniy Vladimirovich #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */ 508efb3719fSKrasnov Arseniy Vladimirovich 509efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_client(const struct test_opts *opts) 510efb3719fSKrasnov Arseniy Vladimirovich { 511efb3719fSKrasnov Arseniy Vladimirovich int fd; 512efb3719fSKrasnov Arseniy Vladimirovich struct timeval tv; 513efb3719fSKrasnov Arseniy Vladimirovich char dummy; 514efb3719fSKrasnov Arseniy Vladimirovich time_t read_enter_ns; 515efb3719fSKrasnov Arseniy Vladimirovich time_t read_overhead_ns; 516efb3719fSKrasnov Arseniy Vladimirovich 517efb3719fSKrasnov Arseniy Vladimirovich fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 518efb3719fSKrasnov Arseniy Vladimirovich if (fd < 0) { 519efb3719fSKrasnov Arseniy Vladimirovich perror("connect"); 520efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 521efb3719fSKrasnov Arseniy Vladimirovich } 522efb3719fSKrasnov Arseniy Vladimirovich 523efb3719fSKrasnov Arseniy Vladimirovich tv.tv_sec = RCVTIMEO_TIMEOUT_SEC; 524efb3719fSKrasnov Arseniy Vladimirovich tv.tv_usec = 0; 525efb3719fSKrasnov Arseniy Vladimirovich 526efb3719fSKrasnov Arseniy Vladimirovich if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) { 5275c338112SArseniy Krasnov perror("setsockopt(SO_RCVTIMEO)"); 528efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 529efb3719fSKrasnov Arseniy Vladimirovich } 530efb3719fSKrasnov Arseniy Vladimirovich 531efb3719fSKrasnov Arseniy Vladimirovich read_enter_ns = current_nsec(); 532efb3719fSKrasnov Arseniy Vladimirovich 533efb3719fSKrasnov Arseniy Vladimirovich if (read(fd, &dummy, sizeof(dummy)) != -1) { 534efb3719fSKrasnov Arseniy Vladimirovich fprintf(stderr, 535efb3719fSKrasnov Arseniy Vladimirovich "expected 'dummy' read(2) failure\n"); 536efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 537efb3719fSKrasnov Arseniy Vladimirovich } 538efb3719fSKrasnov Arseniy Vladimirovich 539efb3719fSKrasnov Arseniy Vladimirovich if (errno != EAGAIN) { 540efb3719fSKrasnov Arseniy Vladimirovich perror("EAGAIN expected"); 541efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 542efb3719fSKrasnov Arseniy Vladimirovich } 543efb3719fSKrasnov Arseniy Vladimirovich 544efb3719fSKrasnov Arseniy Vladimirovich read_overhead_ns = current_nsec() - read_enter_ns - 545efb3719fSKrasnov Arseniy Vladimirovich 1000000000ULL * RCVTIMEO_TIMEOUT_SEC; 546efb3719fSKrasnov Arseniy Vladimirovich 547efb3719fSKrasnov Arseniy Vladimirovich if (read_overhead_ns > READ_OVERHEAD_NSEC) { 548efb3719fSKrasnov Arseniy Vladimirovich fprintf(stderr, 549efb3719fSKrasnov Arseniy Vladimirovich "too much time in read(2), %lu > %i ns\n", 550efb3719fSKrasnov Arseniy Vladimirovich read_overhead_ns, READ_OVERHEAD_NSEC); 551efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 552efb3719fSKrasnov Arseniy Vladimirovich } 553efb3719fSKrasnov Arseniy Vladimirovich 554efb3719fSKrasnov Arseniy Vladimirovich control_writeln("WAITDONE"); 555efb3719fSKrasnov Arseniy Vladimirovich close(fd); 556efb3719fSKrasnov Arseniy Vladimirovich } 557efb3719fSKrasnov Arseniy Vladimirovich 558efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_server(const struct test_opts *opts) 559efb3719fSKrasnov Arseniy Vladimirovich { 560efb3719fSKrasnov Arseniy Vladimirovich int fd; 561efb3719fSKrasnov Arseniy Vladimirovich 562efb3719fSKrasnov Arseniy Vladimirovich fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 563efb3719fSKrasnov Arseniy Vladimirovich if (fd < 0) { 564efb3719fSKrasnov Arseniy Vladimirovich perror("accept"); 565efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 566efb3719fSKrasnov Arseniy Vladimirovich } 567efb3719fSKrasnov Arseniy Vladimirovich 568efb3719fSKrasnov Arseniy Vladimirovich control_expectln("WAITDONE"); 569efb3719fSKrasnov Arseniy Vladimirovich close(fd); 570efb3719fSKrasnov Arseniy Vladimirovich } 571efb3719fSKrasnov Arseniy Vladimirovich 572685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_client(const struct test_opts *opts) 573685a21c3SArseniy Krasnov { 574685a21c3SArseniy Krasnov unsigned long sock_buf_size; 575685a21c3SArseniy Krasnov ssize_t send_size; 576685a21c3SArseniy Krasnov socklen_t len; 577685a21c3SArseniy Krasnov void *data; 578685a21c3SArseniy Krasnov int fd; 579685a21c3SArseniy Krasnov 580685a21c3SArseniy Krasnov len = sizeof(sock_buf_size); 581685a21c3SArseniy Krasnov 582685a21c3SArseniy Krasnov fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 583685a21c3SArseniy Krasnov if (fd < 0) { 584685a21c3SArseniy Krasnov perror("connect"); 585685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 586685a21c3SArseniy Krasnov } 587685a21c3SArseniy Krasnov 588685a21c3SArseniy Krasnov if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, 589685a21c3SArseniy Krasnov &sock_buf_size, &len)) { 590685a21c3SArseniy Krasnov perror("getsockopt"); 591685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 592685a21c3SArseniy Krasnov } 593685a21c3SArseniy Krasnov 594685a21c3SArseniy Krasnov sock_buf_size++; 595685a21c3SArseniy Krasnov 596685a21c3SArseniy Krasnov data = malloc(sock_buf_size); 597685a21c3SArseniy Krasnov if (!data) { 598685a21c3SArseniy Krasnov perror("malloc"); 599685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 600685a21c3SArseniy Krasnov } 601685a21c3SArseniy Krasnov 602685a21c3SArseniy Krasnov send_size = send(fd, data, sock_buf_size, 0); 603685a21c3SArseniy Krasnov if (send_size != -1) { 604685a21c3SArseniy Krasnov fprintf(stderr, "expected 'send(2)' failure, got %zi\n", 605685a21c3SArseniy Krasnov send_size); 606685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 607685a21c3SArseniy Krasnov } 608685a21c3SArseniy Krasnov 609685a21c3SArseniy Krasnov if (errno != EMSGSIZE) { 610685a21c3SArseniy Krasnov fprintf(stderr, "expected EMSGSIZE in 'errno', got %i\n", 611685a21c3SArseniy Krasnov errno); 612685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 613685a21c3SArseniy Krasnov } 614685a21c3SArseniy Krasnov 615685a21c3SArseniy Krasnov control_writeln("CLISENT"); 616685a21c3SArseniy Krasnov 617685a21c3SArseniy Krasnov free(data); 618685a21c3SArseniy Krasnov close(fd); 619685a21c3SArseniy Krasnov } 620685a21c3SArseniy Krasnov 621685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_server(const struct test_opts *opts) 622685a21c3SArseniy Krasnov { 623685a21c3SArseniy Krasnov int fd; 624685a21c3SArseniy Krasnov 625685a21c3SArseniy Krasnov fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 626685a21c3SArseniy Krasnov if (fd < 0) { 627685a21c3SArseniy Krasnov perror("accept"); 628685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 629685a21c3SArseniy Krasnov } 630685a21c3SArseniy Krasnov 631685a21c3SArseniy Krasnov control_expectln("CLISENT"); 632685a21c3SArseniy Krasnov 633685a21c3SArseniy Krasnov close(fd); 634685a21c3SArseniy Krasnov } 635685a21c3SArseniy Krasnov 636e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_1 'a' 637e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_2 'b' 638e89600ebSKrasnov Arseniy Vladimirovich 639e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts) 640e89600ebSKrasnov Arseniy Vladimirovich { 641e89600ebSKrasnov Arseniy Vladimirovich int fd; 642e89600ebSKrasnov Arseniy Vladimirovich unsigned char *buf1; 643e89600ebSKrasnov Arseniy Vladimirovich unsigned char *buf2; 644e89600ebSKrasnov Arseniy Vladimirovich int buf_size = getpagesize() * 3; 645e89600ebSKrasnov Arseniy Vladimirovich 646e89600ebSKrasnov Arseniy Vladimirovich fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 647e89600ebSKrasnov Arseniy Vladimirovich if (fd < 0) { 648e89600ebSKrasnov Arseniy Vladimirovich perror("connect"); 649e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 650e89600ebSKrasnov Arseniy Vladimirovich } 651e89600ebSKrasnov Arseniy Vladimirovich 652e89600ebSKrasnov Arseniy Vladimirovich buf1 = malloc(buf_size); 653e89600ebSKrasnov Arseniy Vladimirovich if (!buf1) { 654e89600ebSKrasnov Arseniy Vladimirovich perror("'malloc()' for 'buf1'"); 655e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 656e89600ebSKrasnov Arseniy Vladimirovich } 657e89600ebSKrasnov Arseniy Vladimirovich 658e89600ebSKrasnov Arseniy Vladimirovich buf2 = malloc(buf_size); 659e89600ebSKrasnov Arseniy Vladimirovich if (!buf2) { 660e89600ebSKrasnov Arseniy Vladimirovich perror("'malloc()' for 'buf2'"); 661e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 662e89600ebSKrasnov Arseniy Vladimirovich } 663e89600ebSKrasnov Arseniy Vladimirovich 664e89600ebSKrasnov Arseniy Vladimirovich memset(buf1, BUF_PATTERN_1, buf_size); 665e89600ebSKrasnov Arseniy Vladimirovich memset(buf2, BUF_PATTERN_2, buf_size); 666e89600ebSKrasnov Arseniy Vladimirovich 667e89600ebSKrasnov Arseniy Vladimirovich if (send(fd, buf1, buf_size, 0) != buf_size) { 668e89600ebSKrasnov Arseniy Vladimirovich perror("send failed"); 669e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 670e89600ebSKrasnov Arseniy Vladimirovich } 671e89600ebSKrasnov Arseniy Vladimirovich 672e89600ebSKrasnov Arseniy Vladimirovich if (send(fd, buf2, buf_size, 0) != buf_size) { 673e89600ebSKrasnov Arseniy Vladimirovich perror("send failed"); 674e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 675e89600ebSKrasnov Arseniy Vladimirovich } 676e89600ebSKrasnov Arseniy Vladimirovich 677e89600ebSKrasnov Arseniy Vladimirovich close(fd); 678e89600ebSKrasnov Arseniy Vladimirovich } 679e89600ebSKrasnov Arseniy Vladimirovich 680e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts) 681e89600ebSKrasnov Arseniy Vladimirovich { 682e89600ebSKrasnov Arseniy Vladimirovich int fd; 683e89600ebSKrasnov Arseniy Vladimirovich unsigned char *broken_buf; 684e89600ebSKrasnov Arseniy Vladimirovich unsigned char *valid_buf; 685e89600ebSKrasnov Arseniy Vladimirovich int page_size = getpagesize(); 686e89600ebSKrasnov Arseniy Vladimirovich int buf_size = page_size * 3; 687e89600ebSKrasnov Arseniy Vladimirovich ssize_t res; 688e89600ebSKrasnov Arseniy Vladimirovich int prot = PROT_READ | PROT_WRITE; 689e89600ebSKrasnov Arseniy Vladimirovich int flags = MAP_PRIVATE | MAP_ANONYMOUS; 690e89600ebSKrasnov Arseniy Vladimirovich int i; 691e89600ebSKrasnov Arseniy Vladimirovich 692e89600ebSKrasnov Arseniy Vladimirovich fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 693e89600ebSKrasnov Arseniy Vladimirovich if (fd < 0) { 694e89600ebSKrasnov Arseniy Vladimirovich perror("accept"); 695e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 696e89600ebSKrasnov Arseniy Vladimirovich } 697e89600ebSKrasnov Arseniy Vladimirovich 698e89600ebSKrasnov Arseniy Vladimirovich /* Setup first buffer. */ 699e89600ebSKrasnov Arseniy Vladimirovich broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0); 700e89600ebSKrasnov Arseniy Vladimirovich if (broken_buf == MAP_FAILED) { 701e89600ebSKrasnov Arseniy Vladimirovich perror("mmap for 'broken_buf'"); 702e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 703e89600ebSKrasnov Arseniy Vladimirovich } 704e89600ebSKrasnov Arseniy Vladimirovich 705e89600ebSKrasnov Arseniy Vladimirovich /* Unmap "hole" in buffer. */ 706e89600ebSKrasnov Arseniy Vladimirovich if (munmap(broken_buf + page_size, page_size)) { 707e89600ebSKrasnov Arseniy Vladimirovich perror("'broken_buf' setup"); 708e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 709e89600ebSKrasnov Arseniy Vladimirovich } 710e89600ebSKrasnov Arseniy Vladimirovich 711e89600ebSKrasnov Arseniy Vladimirovich valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0); 712e89600ebSKrasnov Arseniy Vladimirovich if (valid_buf == MAP_FAILED) { 713e89600ebSKrasnov Arseniy Vladimirovich perror("mmap for 'valid_buf'"); 714e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 715e89600ebSKrasnov Arseniy Vladimirovich } 716e89600ebSKrasnov Arseniy Vladimirovich 717e89600ebSKrasnov Arseniy Vladimirovich /* Try to fill buffer with unmapped middle. */ 718e89600ebSKrasnov Arseniy Vladimirovich res = read(fd, broken_buf, buf_size); 719e89600ebSKrasnov Arseniy Vladimirovich if (res != -1) { 720e89600ebSKrasnov Arseniy Vladimirovich fprintf(stderr, 721e89600ebSKrasnov Arseniy Vladimirovich "expected 'broken_buf' read(2) failure, got %zi\n", 722e89600ebSKrasnov Arseniy Vladimirovich res); 723e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 724e89600ebSKrasnov Arseniy Vladimirovich } 725e89600ebSKrasnov Arseniy Vladimirovich 726e89600ebSKrasnov Arseniy Vladimirovich if (errno != ENOMEM) { 727e89600ebSKrasnov Arseniy Vladimirovich perror("unexpected errno of 'broken_buf'"); 728e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 729e89600ebSKrasnov Arseniy Vladimirovich } 730e89600ebSKrasnov Arseniy Vladimirovich 731e89600ebSKrasnov Arseniy Vladimirovich /* Try to fill valid buffer. */ 732e89600ebSKrasnov Arseniy Vladimirovich res = read(fd, valid_buf, buf_size); 733e89600ebSKrasnov Arseniy Vladimirovich if (res < 0) { 734e89600ebSKrasnov Arseniy Vladimirovich perror("unexpected 'valid_buf' read(2) failure"); 735e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 736e89600ebSKrasnov Arseniy Vladimirovich } 737e89600ebSKrasnov Arseniy Vladimirovich 738e89600ebSKrasnov Arseniy Vladimirovich if (res != buf_size) { 739e89600ebSKrasnov Arseniy Vladimirovich fprintf(stderr, 740e89600ebSKrasnov Arseniy Vladimirovich "invalid 'valid_buf' read(2), expected %i, got %zi\n", 741e89600ebSKrasnov Arseniy Vladimirovich buf_size, res); 742e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 743e89600ebSKrasnov Arseniy Vladimirovich } 744e89600ebSKrasnov Arseniy Vladimirovich 745e89600ebSKrasnov Arseniy Vladimirovich for (i = 0; i < buf_size; i++) { 746e89600ebSKrasnov Arseniy Vladimirovich if (valid_buf[i] != BUF_PATTERN_2) { 747e89600ebSKrasnov Arseniy Vladimirovich fprintf(stderr, 748e89600ebSKrasnov Arseniy Vladimirovich "invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n", 749e89600ebSKrasnov Arseniy Vladimirovich i, BUF_PATTERN_2, valid_buf[i]); 750e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 751e89600ebSKrasnov Arseniy Vladimirovich } 752e89600ebSKrasnov Arseniy Vladimirovich } 753e89600ebSKrasnov Arseniy Vladimirovich 754e89600ebSKrasnov Arseniy Vladimirovich /* Unmap buffers. */ 755e89600ebSKrasnov Arseniy Vladimirovich munmap(broken_buf, page_size); 756e89600ebSKrasnov Arseniy Vladimirovich munmap(broken_buf + page_size * 2, page_size); 757e89600ebSKrasnov Arseniy Vladimirovich munmap(valid_buf, buf_size); 758e89600ebSKrasnov Arseniy Vladimirovich close(fd); 759e89600ebSKrasnov Arseniy Vladimirovich } 760e89600ebSKrasnov Arseniy Vladimirovich 761b1346338SArseniy Krasnov #define RCVLOWAT_BUF_SIZE 128 762b1346338SArseniy Krasnov 763b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_server(const struct test_opts *opts) 764b1346338SArseniy Krasnov { 765b1346338SArseniy Krasnov int fd; 766b1346338SArseniy Krasnov int i; 767b1346338SArseniy Krasnov 768b1346338SArseniy Krasnov fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 769b1346338SArseniy Krasnov if (fd < 0) { 770b1346338SArseniy Krasnov perror("accept"); 771b1346338SArseniy Krasnov exit(EXIT_FAILURE); 772b1346338SArseniy Krasnov } 773b1346338SArseniy Krasnov 774b1346338SArseniy Krasnov /* Send 1 byte. */ 775b1346338SArseniy Krasnov send_byte(fd, 1, 0); 776b1346338SArseniy Krasnov 777b1346338SArseniy Krasnov control_writeln("SRVSENT"); 778b1346338SArseniy Krasnov 779b1346338SArseniy Krasnov /* Wait until client is ready to receive rest of data. */ 780b1346338SArseniy Krasnov control_expectln("CLNSENT"); 781b1346338SArseniy Krasnov 782b1346338SArseniy Krasnov for (i = 0; i < RCVLOWAT_BUF_SIZE - 1; i++) 783b1346338SArseniy Krasnov send_byte(fd, 1, 0); 784b1346338SArseniy Krasnov 785b1346338SArseniy Krasnov /* Keep socket in active state. */ 786b1346338SArseniy Krasnov control_expectln("POLLDONE"); 787b1346338SArseniy Krasnov 788b1346338SArseniy Krasnov close(fd); 789b1346338SArseniy Krasnov } 790b1346338SArseniy Krasnov 791b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_client(const struct test_opts *opts) 792b1346338SArseniy Krasnov { 793b1346338SArseniy Krasnov unsigned long lowat_val = RCVLOWAT_BUF_SIZE; 794b1346338SArseniy Krasnov char buf[RCVLOWAT_BUF_SIZE]; 795b1346338SArseniy Krasnov struct pollfd fds; 796b1346338SArseniy Krasnov ssize_t read_res; 797b1346338SArseniy Krasnov short poll_flags; 798b1346338SArseniy Krasnov int fd; 799b1346338SArseniy Krasnov 800b1346338SArseniy Krasnov fd = vsock_stream_connect(opts->peer_cid, 1234); 801b1346338SArseniy Krasnov if (fd < 0) { 802b1346338SArseniy Krasnov perror("connect"); 803b1346338SArseniy Krasnov exit(EXIT_FAILURE); 804b1346338SArseniy Krasnov } 805b1346338SArseniy Krasnov 806b1346338SArseniy Krasnov if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, 807b1346338SArseniy Krasnov &lowat_val, sizeof(lowat_val))) { 8085c338112SArseniy Krasnov perror("setsockopt(SO_RCVLOWAT)"); 809b1346338SArseniy Krasnov exit(EXIT_FAILURE); 810b1346338SArseniy Krasnov } 811b1346338SArseniy Krasnov 812b1346338SArseniy Krasnov control_expectln("SRVSENT"); 813b1346338SArseniy Krasnov 814b1346338SArseniy Krasnov /* At this point, server sent 1 byte. */ 815b1346338SArseniy Krasnov fds.fd = fd; 816b1346338SArseniy Krasnov poll_flags = POLLIN | POLLRDNORM; 817b1346338SArseniy Krasnov fds.events = poll_flags; 818b1346338SArseniy Krasnov 819b1346338SArseniy Krasnov /* Try to wait for 1 sec. */ 820b1346338SArseniy Krasnov if (poll(&fds, 1, 1000) < 0) { 821b1346338SArseniy Krasnov perror("poll"); 822b1346338SArseniy Krasnov exit(EXIT_FAILURE); 823b1346338SArseniy Krasnov } 824b1346338SArseniy Krasnov 825b1346338SArseniy Krasnov /* poll() must return nothing. */ 826b1346338SArseniy Krasnov if (fds.revents) { 827b1346338SArseniy Krasnov fprintf(stderr, "Unexpected poll result %hx\n", 828b1346338SArseniy Krasnov fds.revents); 829b1346338SArseniy Krasnov exit(EXIT_FAILURE); 830b1346338SArseniy Krasnov } 831b1346338SArseniy Krasnov 832b1346338SArseniy Krasnov /* Tell server to send rest of data. */ 833b1346338SArseniy Krasnov control_writeln("CLNSENT"); 834b1346338SArseniy Krasnov 835b1346338SArseniy Krasnov /* Poll for data. */ 836b1346338SArseniy Krasnov if (poll(&fds, 1, 10000) < 0) { 837b1346338SArseniy Krasnov perror("poll"); 838b1346338SArseniy Krasnov exit(EXIT_FAILURE); 839b1346338SArseniy Krasnov } 840b1346338SArseniy Krasnov 841b1346338SArseniy Krasnov /* Only these two bits are expected. */ 842b1346338SArseniy Krasnov if (fds.revents != poll_flags) { 843b1346338SArseniy Krasnov fprintf(stderr, "Unexpected poll result %hx\n", 844b1346338SArseniy Krasnov fds.revents); 845b1346338SArseniy Krasnov exit(EXIT_FAILURE); 846b1346338SArseniy Krasnov } 847b1346338SArseniy Krasnov 848b1346338SArseniy Krasnov /* Use MSG_DONTWAIT, if call is going to wait, EAGAIN 849b1346338SArseniy Krasnov * will be returned. 850b1346338SArseniy Krasnov */ 851b1346338SArseniy Krasnov read_res = recv(fd, buf, sizeof(buf), MSG_DONTWAIT); 852b1346338SArseniy Krasnov if (read_res != RCVLOWAT_BUF_SIZE) { 853b1346338SArseniy Krasnov fprintf(stderr, "Unexpected recv result %zi\n", 854b1346338SArseniy Krasnov read_res); 855b1346338SArseniy Krasnov exit(EXIT_FAILURE); 856b1346338SArseniy Krasnov } 857b1346338SArseniy Krasnov 858b1346338SArseniy Krasnov control_writeln("POLLDONE"); 859b1346338SArseniy Krasnov 860b1346338SArseniy Krasnov close(fd); 861b1346338SArseniy Krasnov } 862b1346338SArseniy Krasnov 863*7e699d2aSArseniy Krasnov #define INV_BUF_TEST_DATA_LEN 512 864*7e699d2aSArseniy Krasnov 865*7e699d2aSArseniy Krasnov static void test_inv_buf_client(const struct test_opts *opts, bool stream) 866*7e699d2aSArseniy Krasnov { 867*7e699d2aSArseniy Krasnov unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; 868*7e699d2aSArseniy Krasnov ssize_t ret; 869*7e699d2aSArseniy Krasnov int fd; 870*7e699d2aSArseniy Krasnov 871*7e699d2aSArseniy Krasnov if (stream) 872*7e699d2aSArseniy Krasnov fd = vsock_stream_connect(opts->peer_cid, 1234); 873*7e699d2aSArseniy Krasnov else 874*7e699d2aSArseniy Krasnov fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 875*7e699d2aSArseniy Krasnov 876*7e699d2aSArseniy Krasnov if (fd < 0) { 877*7e699d2aSArseniy Krasnov perror("connect"); 878*7e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 879*7e699d2aSArseniy Krasnov } 880*7e699d2aSArseniy Krasnov 881*7e699d2aSArseniy Krasnov control_expectln("SENDDONE"); 882*7e699d2aSArseniy Krasnov 883*7e699d2aSArseniy Krasnov /* Use invalid buffer here. */ 884*7e699d2aSArseniy Krasnov ret = recv(fd, NULL, sizeof(data), 0); 885*7e699d2aSArseniy Krasnov if (ret != -1) { 886*7e699d2aSArseniy Krasnov fprintf(stderr, "expected recv(2) failure, got %zi\n", ret); 887*7e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 888*7e699d2aSArseniy Krasnov } 889*7e699d2aSArseniy Krasnov 890*7e699d2aSArseniy Krasnov if (errno != ENOMEM) { 891*7e699d2aSArseniy Krasnov fprintf(stderr, "unexpected recv(2) errno %d\n", errno); 892*7e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 893*7e699d2aSArseniy Krasnov } 894*7e699d2aSArseniy Krasnov 895*7e699d2aSArseniy Krasnov ret = recv(fd, data, sizeof(data), MSG_DONTWAIT); 896*7e699d2aSArseniy Krasnov 897*7e699d2aSArseniy Krasnov if (stream) { 898*7e699d2aSArseniy Krasnov /* For SOCK_STREAM we must continue reading. */ 899*7e699d2aSArseniy Krasnov if (ret != sizeof(data)) { 900*7e699d2aSArseniy Krasnov fprintf(stderr, "expected recv(2) success, got %zi\n", ret); 901*7e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 902*7e699d2aSArseniy Krasnov } 903*7e699d2aSArseniy Krasnov /* Don't check errno in case of success. */ 904*7e699d2aSArseniy Krasnov } else { 905*7e699d2aSArseniy Krasnov /* For SOCK_SEQPACKET socket's queue must be empty. */ 906*7e699d2aSArseniy Krasnov if (ret != -1) { 907*7e699d2aSArseniy Krasnov fprintf(stderr, "expected recv(2) failure, got %zi\n", ret); 908*7e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 909*7e699d2aSArseniy Krasnov } 910*7e699d2aSArseniy Krasnov 911*7e699d2aSArseniy Krasnov if (errno != EAGAIN) { 912*7e699d2aSArseniy Krasnov fprintf(stderr, "unexpected recv(2) errno %d\n", errno); 913*7e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 914*7e699d2aSArseniy Krasnov } 915*7e699d2aSArseniy Krasnov } 916*7e699d2aSArseniy Krasnov 917*7e699d2aSArseniy Krasnov control_writeln("DONE"); 918*7e699d2aSArseniy Krasnov 919*7e699d2aSArseniy Krasnov close(fd); 920*7e699d2aSArseniy Krasnov } 921*7e699d2aSArseniy Krasnov 922*7e699d2aSArseniy Krasnov static void test_inv_buf_server(const struct test_opts *opts, bool stream) 923*7e699d2aSArseniy Krasnov { 924*7e699d2aSArseniy Krasnov unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; 925*7e699d2aSArseniy Krasnov ssize_t res; 926*7e699d2aSArseniy Krasnov int fd; 927*7e699d2aSArseniy Krasnov 928*7e699d2aSArseniy Krasnov if (stream) 929*7e699d2aSArseniy Krasnov fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 930*7e699d2aSArseniy Krasnov else 931*7e699d2aSArseniy Krasnov fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 932*7e699d2aSArseniy Krasnov 933*7e699d2aSArseniy Krasnov if (fd < 0) { 934*7e699d2aSArseniy Krasnov perror("accept"); 935*7e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 936*7e699d2aSArseniy Krasnov } 937*7e699d2aSArseniy Krasnov 938*7e699d2aSArseniy Krasnov res = send(fd, data, sizeof(data), 0); 939*7e699d2aSArseniy Krasnov if (res != sizeof(data)) { 940*7e699d2aSArseniy Krasnov fprintf(stderr, "unexpected send(2) result %zi\n", res); 941*7e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 942*7e699d2aSArseniy Krasnov } 943*7e699d2aSArseniy Krasnov 944*7e699d2aSArseniy Krasnov control_writeln("SENDDONE"); 945*7e699d2aSArseniy Krasnov 946*7e699d2aSArseniy Krasnov control_expectln("DONE"); 947*7e699d2aSArseniy Krasnov 948*7e699d2aSArseniy Krasnov close(fd); 949*7e699d2aSArseniy Krasnov } 950*7e699d2aSArseniy Krasnov 951*7e699d2aSArseniy Krasnov static void test_stream_inv_buf_client(const struct test_opts *opts) 952*7e699d2aSArseniy Krasnov { 953*7e699d2aSArseniy Krasnov test_inv_buf_client(opts, true); 954*7e699d2aSArseniy Krasnov } 955*7e699d2aSArseniy Krasnov 956*7e699d2aSArseniy Krasnov static void test_stream_inv_buf_server(const struct test_opts *opts) 957*7e699d2aSArseniy Krasnov { 958*7e699d2aSArseniy Krasnov test_inv_buf_server(opts, true); 959*7e699d2aSArseniy Krasnov } 960*7e699d2aSArseniy Krasnov 961*7e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_client(const struct test_opts *opts) 962*7e699d2aSArseniy Krasnov { 963*7e699d2aSArseniy Krasnov test_inv_buf_client(opts, false); 964*7e699d2aSArseniy Krasnov } 965*7e699d2aSArseniy Krasnov 966*7e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_server(const struct test_opts *opts) 967*7e699d2aSArseniy Krasnov { 968*7e699d2aSArseniy Krasnov test_inv_buf_server(opts, false); 969*7e699d2aSArseniy Krasnov } 970*7e699d2aSArseniy Krasnov 971cdbcc18dSStefan Hajnoczi static struct test_case test_cases[] = { 972cdbcc18dSStefan Hajnoczi { 973cdbcc18dSStefan Hajnoczi .name = "SOCK_STREAM connection reset", 974cdbcc18dSStefan Hajnoczi .run_client = test_stream_connection_reset, 975cdbcc18dSStefan Hajnoczi }, 976cdbcc18dSStefan Hajnoczi { 9779de9f7d1SSebastien Boeuf .name = "SOCK_STREAM bind only", 9789de9f7d1SSebastien Boeuf .run_client = test_stream_bind_only_client, 9799de9f7d1SSebastien Boeuf .run_server = test_stream_bind_only_server, 9809de9f7d1SSebastien Boeuf }, 9819de9f7d1SSebastien Boeuf { 982cdbcc18dSStefan Hajnoczi .name = "SOCK_STREAM client close", 983cdbcc18dSStefan Hajnoczi .run_client = test_stream_client_close_client, 984cdbcc18dSStefan Hajnoczi .run_server = test_stream_client_close_server, 985cdbcc18dSStefan Hajnoczi }, 986cdbcc18dSStefan Hajnoczi { 987cdbcc18dSStefan Hajnoczi .name = "SOCK_STREAM server close", 988cdbcc18dSStefan Hajnoczi .run_client = test_stream_server_close_client, 989cdbcc18dSStefan Hajnoczi .run_server = test_stream_server_close_server, 990cdbcc18dSStefan Hajnoczi }, 991cdbcc18dSStefan Hajnoczi { 992cdbcc18dSStefan Hajnoczi .name = "SOCK_STREAM multiple connections", 993cdbcc18dSStefan Hajnoczi .run_client = test_stream_multiconn_client, 994cdbcc18dSStefan Hajnoczi .run_server = test_stream_multiconn_server, 995cdbcc18dSStefan Hajnoczi }, 996d6269a93SStefano Garzarella { 997d6269a93SStefano Garzarella .name = "SOCK_STREAM MSG_PEEK", 998d6269a93SStefano Garzarella .run_client = test_stream_msg_peek_client, 999d6269a93SStefano Garzarella .run_server = test_stream_msg_peek_server, 1000d6269a93SStefano Garzarella }, 100141b792d7SArseny Krasnov { 100241b792d7SArseny Krasnov .name = "SOCK_SEQPACKET msg bounds", 100341b792d7SArseny Krasnov .run_client = test_seqpacket_msg_bounds_client, 100441b792d7SArseny Krasnov .run_server = test_seqpacket_msg_bounds_server, 100541b792d7SArseny Krasnov }, 100641b792d7SArseny Krasnov { 100741b792d7SArseny Krasnov .name = "SOCK_SEQPACKET MSG_TRUNC flag", 100841b792d7SArseny Krasnov .run_client = test_seqpacket_msg_trunc_client, 100941b792d7SArseny Krasnov .run_server = test_seqpacket_msg_trunc_server, 101041b792d7SArseny Krasnov }, 1011efb3719fSKrasnov Arseniy Vladimirovich { 1012efb3719fSKrasnov Arseniy Vladimirovich .name = "SOCK_SEQPACKET timeout", 1013efb3719fSKrasnov Arseniy Vladimirovich .run_client = test_seqpacket_timeout_client, 1014efb3719fSKrasnov Arseniy Vladimirovich .run_server = test_seqpacket_timeout_server, 1015efb3719fSKrasnov Arseniy Vladimirovich }, 1016e89600ebSKrasnov Arseniy Vladimirovich { 1017e89600ebSKrasnov Arseniy Vladimirovich .name = "SOCK_SEQPACKET invalid receive buffer", 1018e89600ebSKrasnov Arseniy Vladimirovich .run_client = test_seqpacket_invalid_rec_buffer_client, 1019e89600ebSKrasnov Arseniy Vladimirovich .run_server = test_seqpacket_invalid_rec_buffer_server, 1020e89600ebSKrasnov Arseniy Vladimirovich }, 1021b1346338SArseniy Krasnov { 1022b1346338SArseniy Krasnov .name = "SOCK_STREAM poll() + SO_RCVLOWAT", 1023b1346338SArseniy Krasnov .run_client = test_stream_poll_rcvlowat_client, 1024b1346338SArseniy Krasnov .run_server = test_stream_poll_rcvlowat_server, 1025b1346338SArseniy Krasnov }, 1026685a21c3SArseniy Krasnov { 1027685a21c3SArseniy Krasnov .name = "SOCK_SEQPACKET big message", 1028685a21c3SArseniy Krasnov .run_client = test_seqpacket_bigmsg_client, 1029685a21c3SArseniy Krasnov .run_server = test_seqpacket_bigmsg_server, 1030685a21c3SArseniy Krasnov }, 1031*7e699d2aSArseniy Krasnov { 1032*7e699d2aSArseniy Krasnov .name = "SOCK_STREAM test invalid buffer", 1033*7e699d2aSArseniy Krasnov .run_client = test_stream_inv_buf_client, 1034*7e699d2aSArseniy Krasnov .run_server = test_stream_inv_buf_server, 1035*7e699d2aSArseniy Krasnov }, 1036*7e699d2aSArseniy Krasnov { 1037*7e699d2aSArseniy Krasnov .name = "SOCK_SEQPACKET test invalid buffer", 1038*7e699d2aSArseniy Krasnov .run_client = test_seqpacket_inv_buf_client, 1039*7e699d2aSArseniy Krasnov .run_server = test_seqpacket_inv_buf_server, 1040*7e699d2aSArseniy Krasnov }, 1041cdbcc18dSStefan Hajnoczi {}, 1042cdbcc18dSStefan Hajnoczi }; 1043cdbcc18dSStefan Hajnoczi 1044cdbcc18dSStefan Hajnoczi static const char optstring[] = ""; 1045cdbcc18dSStefan Hajnoczi static const struct option longopts[] = { 1046cdbcc18dSStefan Hajnoczi { 1047cdbcc18dSStefan Hajnoczi .name = "control-host", 1048cdbcc18dSStefan Hajnoczi .has_arg = required_argument, 1049cdbcc18dSStefan Hajnoczi .val = 'H', 1050cdbcc18dSStefan Hajnoczi }, 1051cdbcc18dSStefan Hajnoczi { 1052cdbcc18dSStefan Hajnoczi .name = "control-port", 1053cdbcc18dSStefan Hajnoczi .has_arg = required_argument, 1054cdbcc18dSStefan Hajnoczi .val = 'P', 1055cdbcc18dSStefan Hajnoczi }, 1056cdbcc18dSStefan Hajnoczi { 1057cdbcc18dSStefan Hajnoczi .name = "mode", 1058cdbcc18dSStefan Hajnoczi .has_arg = required_argument, 1059cdbcc18dSStefan Hajnoczi .val = 'm', 1060cdbcc18dSStefan Hajnoczi }, 1061cdbcc18dSStefan Hajnoczi { 1062cdbcc18dSStefan Hajnoczi .name = "peer-cid", 1063cdbcc18dSStefan Hajnoczi .has_arg = required_argument, 1064cdbcc18dSStefan Hajnoczi .val = 'p', 1065cdbcc18dSStefan Hajnoczi }, 1066cdbcc18dSStefan Hajnoczi { 10675a2b2425SStefano Garzarella .name = "list", 10685a2b2425SStefano Garzarella .has_arg = no_argument, 10695a2b2425SStefano Garzarella .val = 'l', 10705a2b2425SStefano Garzarella }, 10715a2b2425SStefano Garzarella { 10725a2b2425SStefano Garzarella .name = "skip", 10735a2b2425SStefano Garzarella .has_arg = required_argument, 10745a2b2425SStefano Garzarella .val = 's', 10755a2b2425SStefano Garzarella }, 10765a2b2425SStefano Garzarella { 1077cdbcc18dSStefan Hajnoczi .name = "help", 1078cdbcc18dSStefan Hajnoczi .has_arg = no_argument, 1079cdbcc18dSStefan Hajnoczi .val = '?', 1080cdbcc18dSStefan Hajnoczi }, 1081cdbcc18dSStefan Hajnoczi {}, 1082cdbcc18dSStefan Hajnoczi }; 1083cdbcc18dSStefan Hajnoczi 1084cdbcc18dSStefan Hajnoczi static void usage(void) 1085cdbcc18dSStefan Hajnoczi { 10865a2b2425SStefano Garzarella fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n" 1087cdbcc18dSStefan Hajnoczi "\n" 1088cdbcc18dSStefan Hajnoczi " Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n" 1089cdbcc18dSStefan Hajnoczi " Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" 1090cdbcc18dSStefan Hajnoczi "\n" 1091cdbcc18dSStefan Hajnoczi "Run vsock.ko tests. Must be launched in both guest\n" 1092cdbcc18dSStefan Hajnoczi "and host. One side must use --mode=client and\n" 1093cdbcc18dSStefan Hajnoczi "the other side must use --mode=server.\n" 1094cdbcc18dSStefan Hajnoczi "\n" 1095cdbcc18dSStefan Hajnoczi "A TCP control socket connection is used to coordinate tests\n" 1096cdbcc18dSStefan Hajnoczi "between the client and the server. The server requires a\n" 1097cdbcc18dSStefan Hajnoczi "listen address and the client requires an address to\n" 1098cdbcc18dSStefan Hajnoczi "connect to.\n" 1099cdbcc18dSStefan Hajnoczi "\n" 11008d00b93fSStefano Garzarella "The CID of the other side must be given with --peer-cid=<cid>.\n" 11018d00b93fSStefano Garzarella "\n" 11028d00b93fSStefano Garzarella "Options:\n" 11038d00b93fSStefano Garzarella " --help This help message\n" 11048d00b93fSStefano Garzarella " --control-host <host> Server IP address to connect to\n" 11058d00b93fSStefano Garzarella " --control-port <port> Server port to listen on/connect to\n" 11068d00b93fSStefano Garzarella " --mode client|server Server or client mode\n" 11078d00b93fSStefano Garzarella " --peer-cid <cid> CID of the other side\n" 11088d00b93fSStefano Garzarella " --list List of tests that will be executed\n" 11098d00b93fSStefano Garzarella " --skip <test_id> Test ID to skip;\n" 11108d00b93fSStefano Garzarella " use multiple --skip options to skip more tests\n" 11118d00b93fSStefano Garzarella ); 1112cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 1113cdbcc18dSStefan Hajnoczi } 1114cdbcc18dSStefan Hajnoczi 1115cdbcc18dSStefan Hajnoczi int main(int argc, char **argv) 1116cdbcc18dSStefan Hajnoczi { 1117cdbcc18dSStefan Hajnoczi const char *control_host = NULL; 1118cdbcc18dSStefan Hajnoczi const char *control_port = NULL; 1119cdbcc18dSStefan Hajnoczi struct test_opts opts = { 1120cdbcc18dSStefan Hajnoczi .mode = TEST_MODE_UNSET, 1121cdbcc18dSStefan Hajnoczi .peer_cid = VMADDR_CID_ANY, 1122cdbcc18dSStefan Hajnoczi }; 1123cdbcc18dSStefan Hajnoczi 11245c338112SArseniy Krasnov srand(time(NULL)); 1125cdbcc18dSStefan Hajnoczi init_signals(); 1126cdbcc18dSStefan Hajnoczi 1127cdbcc18dSStefan Hajnoczi for (;;) { 1128cdbcc18dSStefan Hajnoczi int opt = getopt_long(argc, argv, optstring, longopts, NULL); 1129cdbcc18dSStefan Hajnoczi 1130cdbcc18dSStefan Hajnoczi if (opt == -1) 1131cdbcc18dSStefan Hajnoczi break; 1132cdbcc18dSStefan Hajnoczi 1133cdbcc18dSStefan Hajnoczi switch (opt) { 1134cdbcc18dSStefan Hajnoczi case 'H': 1135cdbcc18dSStefan Hajnoczi control_host = optarg; 1136cdbcc18dSStefan Hajnoczi break; 1137cdbcc18dSStefan Hajnoczi case 'm': 1138cdbcc18dSStefan Hajnoczi if (strcmp(optarg, "client") == 0) 1139cdbcc18dSStefan Hajnoczi opts.mode = TEST_MODE_CLIENT; 1140cdbcc18dSStefan Hajnoczi else if (strcmp(optarg, "server") == 0) 1141cdbcc18dSStefan Hajnoczi opts.mode = TEST_MODE_SERVER; 1142cdbcc18dSStefan Hajnoczi else { 1143cdbcc18dSStefan Hajnoczi fprintf(stderr, "--mode must be \"client\" or \"server\"\n"); 1144cdbcc18dSStefan Hajnoczi return EXIT_FAILURE; 1145cdbcc18dSStefan Hajnoczi } 1146cdbcc18dSStefan Hajnoczi break; 1147cdbcc18dSStefan Hajnoczi case 'p': 1148cdbcc18dSStefan Hajnoczi opts.peer_cid = parse_cid(optarg); 1149cdbcc18dSStefan Hajnoczi break; 1150cdbcc18dSStefan Hajnoczi case 'P': 1151cdbcc18dSStefan Hajnoczi control_port = optarg; 1152cdbcc18dSStefan Hajnoczi break; 11535a2b2425SStefano Garzarella case 'l': 11545a2b2425SStefano Garzarella list_tests(test_cases); 11555a2b2425SStefano Garzarella break; 11565a2b2425SStefano Garzarella case 's': 11575a2b2425SStefano Garzarella skip_test(test_cases, ARRAY_SIZE(test_cases) - 1, 11585a2b2425SStefano Garzarella optarg); 11595a2b2425SStefano Garzarella break; 1160cdbcc18dSStefan Hajnoczi case '?': 1161cdbcc18dSStefan Hajnoczi default: 1162cdbcc18dSStefan Hajnoczi usage(); 1163cdbcc18dSStefan Hajnoczi } 1164cdbcc18dSStefan Hajnoczi } 1165cdbcc18dSStefan Hajnoczi 1166cdbcc18dSStefan Hajnoczi if (!control_port) 1167cdbcc18dSStefan Hajnoczi usage(); 1168cdbcc18dSStefan Hajnoczi if (opts.mode == TEST_MODE_UNSET) 1169cdbcc18dSStefan Hajnoczi usage(); 1170cdbcc18dSStefan Hajnoczi if (opts.peer_cid == VMADDR_CID_ANY) 1171cdbcc18dSStefan Hajnoczi usage(); 1172cdbcc18dSStefan Hajnoczi 1173cdbcc18dSStefan Hajnoczi if (!control_host) { 1174cdbcc18dSStefan Hajnoczi if (opts.mode != TEST_MODE_SERVER) 1175cdbcc18dSStefan Hajnoczi usage(); 1176cdbcc18dSStefan Hajnoczi control_host = "0.0.0.0"; 1177cdbcc18dSStefan Hajnoczi } 1178cdbcc18dSStefan Hajnoczi 1179cdbcc18dSStefan Hajnoczi control_init(control_host, control_port, 1180cdbcc18dSStefan Hajnoczi opts.mode == TEST_MODE_SERVER); 1181cdbcc18dSStefan Hajnoczi 1182cdbcc18dSStefan Hajnoczi run_tests(test_cases, &opts); 1183cdbcc18dSStefan Hajnoczi 1184cdbcc18dSStefan Hajnoczi control_cleanup(); 1185cdbcc18dSStefan Hajnoczi return EXIT_SUCCESS; 1186cdbcc18dSStefan Hajnoczi } 1187