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 258587ed79fSArseniy Krasnov #define MSG_PEEK_BUF_LEN 64 259587ed79fSArseniy Krasnov 260*8a0697f2SArseniy Krasnov static void test_msg_peek_client(const struct test_opts *opts, 261*8a0697f2SArseniy Krasnov bool seqpacket) 262d6269a93SStefano Garzarella { 263587ed79fSArseniy Krasnov unsigned char buf[MSG_PEEK_BUF_LEN]; 264587ed79fSArseniy Krasnov ssize_t send_size; 265d6269a93SStefano Garzarella int fd; 266587ed79fSArseniy Krasnov int i; 267d6269a93SStefano Garzarella 268*8a0697f2SArseniy Krasnov if (seqpacket) 269*8a0697f2SArseniy Krasnov fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 270*8a0697f2SArseniy Krasnov else 271d6269a93SStefano Garzarella fd = vsock_stream_connect(opts->peer_cid, 1234); 272*8a0697f2SArseniy Krasnov 273d6269a93SStefano Garzarella if (fd < 0) { 274d6269a93SStefano Garzarella perror("connect"); 275d6269a93SStefano Garzarella exit(EXIT_FAILURE); 276d6269a93SStefano Garzarella } 277d6269a93SStefano Garzarella 278587ed79fSArseniy Krasnov for (i = 0; i < sizeof(buf); i++) 279587ed79fSArseniy Krasnov buf[i] = rand() & 0xFF; 280587ed79fSArseniy Krasnov 281587ed79fSArseniy Krasnov control_expectln("SRVREADY"); 282587ed79fSArseniy Krasnov 283587ed79fSArseniy Krasnov send_size = send(fd, buf, sizeof(buf), 0); 284587ed79fSArseniy Krasnov 285587ed79fSArseniy Krasnov if (send_size < 0) { 286587ed79fSArseniy Krasnov perror("send"); 287587ed79fSArseniy Krasnov exit(EXIT_FAILURE); 288587ed79fSArseniy Krasnov } 289587ed79fSArseniy Krasnov 290587ed79fSArseniy Krasnov if (send_size != sizeof(buf)) { 291587ed79fSArseniy Krasnov fprintf(stderr, "Invalid send size %zi\n", send_size); 292587ed79fSArseniy Krasnov exit(EXIT_FAILURE); 293587ed79fSArseniy Krasnov } 294587ed79fSArseniy Krasnov 295d6269a93SStefano Garzarella close(fd); 296d6269a93SStefano Garzarella } 297d6269a93SStefano Garzarella 298*8a0697f2SArseniy Krasnov static void test_msg_peek_server(const struct test_opts *opts, 299*8a0697f2SArseniy Krasnov bool seqpacket) 300d6269a93SStefano Garzarella { 301587ed79fSArseniy Krasnov unsigned char buf_half[MSG_PEEK_BUF_LEN / 2]; 302587ed79fSArseniy Krasnov unsigned char buf_normal[MSG_PEEK_BUF_LEN]; 303587ed79fSArseniy Krasnov unsigned char buf_peek[MSG_PEEK_BUF_LEN]; 304587ed79fSArseniy Krasnov ssize_t res; 305d6269a93SStefano Garzarella int fd; 306d6269a93SStefano Garzarella 307*8a0697f2SArseniy Krasnov if (seqpacket) 308*8a0697f2SArseniy Krasnov fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 309*8a0697f2SArseniy Krasnov else 310d6269a93SStefano Garzarella fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 311*8a0697f2SArseniy Krasnov 312d6269a93SStefano Garzarella if (fd < 0) { 313d6269a93SStefano Garzarella perror("accept"); 314d6269a93SStefano Garzarella exit(EXIT_FAILURE); 315d6269a93SStefano Garzarella } 316d6269a93SStefano Garzarella 317587ed79fSArseniy Krasnov /* Peek from empty socket. */ 318587ed79fSArseniy Krasnov res = recv(fd, buf_peek, sizeof(buf_peek), MSG_PEEK | MSG_DONTWAIT); 319587ed79fSArseniy Krasnov if (res != -1) { 320587ed79fSArseniy Krasnov fprintf(stderr, "expected recv(2) failure, got %zi\n", res); 321587ed79fSArseniy Krasnov exit(EXIT_FAILURE); 322587ed79fSArseniy Krasnov } 323587ed79fSArseniy Krasnov 324587ed79fSArseniy Krasnov if (errno != EAGAIN) { 325587ed79fSArseniy Krasnov perror("EAGAIN expected"); 326587ed79fSArseniy Krasnov exit(EXIT_FAILURE); 327587ed79fSArseniy Krasnov } 328587ed79fSArseniy Krasnov 329587ed79fSArseniy Krasnov control_writeln("SRVREADY"); 330587ed79fSArseniy Krasnov 331587ed79fSArseniy Krasnov /* Peek part of data. */ 332587ed79fSArseniy Krasnov res = recv(fd, buf_half, sizeof(buf_half), MSG_PEEK); 333587ed79fSArseniy Krasnov if (res != sizeof(buf_half)) { 334587ed79fSArseniy Krasnov fprintf(stderr, "recv(2) + MSG_PEEK, expected %zu, got %zi\n", 335587ed79fSArseniy Krasnov sizeof(buf_half), res); 336587ed79fSArseniy Krasnov exit(EXIT_FAILURE); 337587ed79fSArseniy Krasnov } 338587ed79fSArseniy Krasnov 339587ed79fSArseniy Krasnov /* Peek whole data. */ 340587ed79fSArseniy Krasnov res = recv(fd, buf_peek, sizeof(buf_peek), MSG_PEEK); 341587ed79fSArseniy Krasnov if (res != sizeof(buf_peek)) { 342587ed79fSArseniy Krasnov fprintf(stderr, "recv(2) + MSG_PEEK, expected %zu, got %zi\n", 343587ed79fSArseniy Krasnov sizeof(buf_peek), res); 344587ed79fSArseniy Krasnov exit(EXIT_FAILURE); 345587ed79fSArseniy Krasnov } 346587ed79fSArseniy Krasnov 347587ed79fSArseniy Krasnov /* Compare partial and full peek. */ 348587ed79fSArseniy Krasnov if (memcmp(buf_half, buf_peek, sizeof(buf_half))) { 349587ed79fSArseniy Krasnov fprintf(stderr, "Partial peek data mismatch\n"); 350587ed79fSArseniy Krasnov exit(EXIT_FAILURE); 351587ed79fSArseniy Krasnov } 352587ed79fSArseniy Krasnov 353*8a0697f2SArseniy Krasnov if (seqpacket) { 354*8a0697f2SArseniy Krasnov /* This type of socket supports MSG_TRUNC flag, 355*8a0697f2SArseniy Krasnov * so check it with MSG_PEEK. We must get length 356*8a0697f2SArseniy Krasnov * of the message. 357*8a0697f2SArseniy Krasnov */ 358*8a0697f2SArseniy Krasnov res = recv(fd, buf_half, sizeof(buf_half), MSG_PEEK | 359*8a0697f2SArseniy Krasnov MSG_TRUNC); 360*8a0697f2SArseniy Krasnov if (res != sizeof(buf_peek)) { 361*8a0697f2SArseniy Krasnov fprintf(stderr, 362*8a0697f2SArseniy Krasnov "recv(2) + MSG_PEEK | MSG_TRUNC, exp %zu, got %zi\n", 363*8a0697f2SArseniy Krasnov sizeof(buf_half), res); 364*8a0697f2SArseniy Krasnov exit(EXIT_FAILURE); 365*8a0697f2SArseniy Krasnov } 366*8a0697f2SArseniy Krasnov } 367*8a0697f2SArseniy Krasnov 368587ed79fSArseniy Krasnov res = recv(fd, buf_normal, sizeof(buf_normal), 0); 369587ed79fSArseniy Krasnov if (res != sizeof(buf_normal)) { 370587ed79fSArseniy Krasnov fprintf(stderr, "recv(2), expected %zu, got %zi\n", 371587ed79fSArseniy Krasnov sizeof(buf_normal), res); 372587ed79fSArseniy Krasnov exit(EXIT_FAILURE); 373587ed79fSArseniy Krasnov } 374587ed79fSArseniy Krasnov 375587ed79fSArseniy Krasnov /* Compare full peek and normal read. */ 376587ed79fSArseniy Krasnov if (memcmp(buf_peek, buf_normal, sizeof(buf_peek))) { 377587ed79fSArseniy Krasnov fprintf(stderr, "Full peek data mismatch\n"); 378587ed79fSArseniy Krasnov exit(EXIT_FAILURE); 379587ed79fSArseniy Krasnov } 380587ed79fSArseniy Krasnov 381d6269a93SStefano Garzarella close(fd); 382d6269a93SStefano Garzarella } 383d6269a93SStefano Garzarella 384*8a0697f2SArseniy Krasnov static void test_stream_msg_peek_client(const struct test_opts *opts) 385*8a0697f2SArseniy Krasnov { 386*8a0697f2SArseniy Krasnov return test_msg_peek_client(opts, false); 387*8a0697f2SArseniy Krasnov } 388*8a0697f2SArseniy Krasnov 389*8a0697f2SArseniy Krasnov static void test_stream_msg_peek_server(const struct test_opts *opts) 390*8a0697f2SArseniy Krasnov { 391*8a0697f2SArseniy Krasnov return test_msg_peek_server(opts, false); 392*8a0697f2SArseniy Krasnov } 393*8a0697f2SArseniy Krasnov 3945c338112SArseniy Krasnov #define SOCK_BUF_SIZE (2 * 1024 * 1024) 3955c338112SArseniy Krasnov #define MAX_MSG_SIZE (32 * 1024) 3965c338112SArseniy Krasnov 39741b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) 39841b792d7SArseny Krasnov { 3995c338112SArseniy Krasnov unsigned long curr_hash; 4005c338112SArseniy Krasnov int page_size; 4015c338112SArseniy Krasnov int msg_count; 40241b792d7SArseny Krasnov int fd; 40341b792d7SArseny Krasnov 40441b792d7SArseny Krasnov fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 40541b792d7SArseny Krasnov if (fd < 0) { 40641b792d7SArseny Krasnov perror("connect"); 40741b792d7SArseny Krasnov exit(EXIT_FAILURE); 40841b792d7SArseny Krasnov } 40941b792d7SArseny Krasnov 4105c338112SArseniy Krasnov /* Wait, until receiver sets buffer size. */ 4115c338112SArseniy Krasnov control_expectln("SRVREADY"); 4125c338112SArseniy Krasnov 4135c338112SArseniy Krasnov curr_hash = 0; 4145c338112SArseniy Krasnov page_size = getpagesize(); 4155c338112SArseniy Krasnov msg_count = SOCK_BUF_SIZE / MAX_MSG_SIZE; 4165c338112SArseniy Krasnov 4175c338112SArseniy Krasnov for (int i = 0; i < msg_count; i++) { 4185c338112SArseniy Krasnov ssize_t send_size; 4195c338112SArseniy Krasnov size_t buf_size; 4205c338112SArseniy Krasnov int flags; 4215c338112SArseniy Krasnov void *buf; 4225c338112SArseniy Krasnov 4235c338112SArseniy Krasnov /* Use "small" buffers and "big" buffers. */ 4245c338112SArseniy Krasnov if (i & 1) 4255c338112SArseniy Krasnov buf_size = page_size + 4265c338112SArseniy Krasnov (rand() % (MAX_MSG_SIZE - page_size)); 4275c338112SArseniy Krasnov else 4285c338112SArseniy Krasnov buf_size = 1 + (rand() % page_size); 4295c338112SArseniy Krasnov 4305c338112SArseniy Krasnov buf = malloc(buf_size); 4315c338112SArseniy Krasnov 4325c338112SArseniy Krasnov if (!buf) { 4335c338112SArseniy Krasnov perror("malloc"); 4345c338112SArseniy Krasnov exit(EXIT_FAILURE); 4355c338112SArseniy Krasnov } 4365c338112SArseniy Krasnov 4375c338112SArseniy Krasnov memset(buf, rand() & 0xff, buf_size); 4385c338112SArseniy Krasnov /* Set at least one MSG_EOR + some random. */ 4395c338112SArseniy Krasnov if (i == (msg_count / 2) || (rand() & 1)) { 4405c338112SArseniy Krasnov flags = MSG_EOR; 4415c338112SArseniy Krasnov curr_hash++; 4425c338112SArseniy Krasnov } else { 4435c338112SArseniy Krasnov flags = 0; 4445c338112SArseniy Krasnov } 4455c338112SArseniy Krasnov 4465c338112SArseniy Krasnov send_size = send(fd, buf, buf_size, flags); 4475c338112SArseniy Krasnov 4485c338112SArseniy Krasnov if (send_size < 0) { 4495c338112SArseniy Krasnov perror("send"); 4505c338112SArseniy Krasnov exit(EXIT_FAILURE); 4515c338112SArseniy Krasnov } 4525c338112SArseniy Krasnov 4535c338112SArseniy Krasnov if (send_size != buf_size) { 4545c338112SArseniy Krasnov fprintf(stderr, "Invalid send size\n"); 4555c338112SArseniy Krasnov exit(EXIT_FAILURE); 4565c338112SArseniy Krasnov } 4575c338112SArseniy Krasnov 4585c338112SArseniy Krasnov /* 4595c338112SArseniy Krasnov * Hash sum is computed at both client and server in 4605c338112SArseniy Krasnov * the same way: 4615c338112SArseniy Krasnov * H += hash('message data') 4625c338112SArseniy Krasnov * Such hash "controls" both data integrity and message 4635c338112SArseniy Krasnov * bounds. After data exchange, both sums are compared 4645c338112SArseniy Krasnov * using control socket, and if message bounds wasn't 4655c338112SArseniy Krasnov * broken - two values must be equal. 4665c338112SArseniy Krasnov */ 4675c338112SArseniy Krasnov curr_hash += hash_djb2(buf, buf_size); 4685c338112SArseniy Krasnov free(buf); 4695c338112SArseniy Krasnov } 47041b792d7SArseny Krasnov 47141b792d7SArseny Krasnov control_writeln("SENDDONE"); 4725c338112SArseniy Krasnov control_writeulong(curr_hash); 47341b792d7SArseny Krasnov close(fd); 47441b792d7SArseny Krasnov } 47541b792d7SArseny Krasnov 47641b792d7SArseny Krasnov static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) 47741b792d7SArseny Krasnov { 4785c338112SArseniy Krasnov unsigned long sock_buf_size; 4795c338112SArseniy Krasnov unsigned long remote_hash; 4805c338112SArseniy Krasnov unsigned long curr_hash; 48141b792d7SArseny Krasnov int fd; 4825c338112SArseniy Krasnov char buf[MAX_MSG_SIZE]; 48341b792d7SArseny Krasnov struct msghdr msg = {0}; 48441b792d7SArseny Krasnov struct iovec iov = {0}; 48541b792d7SArseny Krasnov 48641b792d7SArseny Krasnov fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 48741b792d7SArseny Krasnov if (fd < 0) { 48841b792d7SArseny Krasnov perror("accept"); 48941b792d7SArseny Krasnov exit(EXIT_FAILURE); 49041b792d7SArseny Krasnov } 49141b792d7SArseny Krasnov 4925c338112SArseniy Krasnov sock_buf_size = SOCK_BUF_SIZE; 4935c338112SArseniy Krasnov 4945c338112SArseniy Krasnov if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, 4955c338112SArseniy Krasnov &sock_buf_size, sizeof(sock_buf_size))) { 4965c338112SArseniy Krasnov perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)"); 4975c338112SArseniy Krasnov exit(EXIT_FAILURE); 4985c338112SArseniy Krasnov } 4995c338112SArseniy Krasnov 5005c338112SArseniy Krasnov if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, 5015c338112SArseniy Krasnov &sock_buf_size, sizeof(sock_buf_size))) { 5025c338112SArseniy Krasnov perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)"); 5035c338112SArseniy Krasnov exit(EXIT_FAILURE); 5045c338112SArseniy Krasnov } 5055c338112SArseniy Krasnov 5065c338112SArseniy Krasnov /* Ready to receive data. */ 5075c338112SArseniy Krasnov control_writeln("SRVREADY"); 5085c338112SArseniy Krasnov /* Wait, until peer sends whole data. */ 50941b792d7SArseny Krasnov control_expectln("SENDDONE"); 51041b792d7SArseny Krasnov iov.iov_base = buf; 51141b792d7SArseny Krasnov iov.iov_len = sizeof(buf); 51241b792d7SArseny Krasnov msg.msg_iov = &iov; 51341b792d7SArseny Krasnov msg.msg_iovlen = 1; 51441b792d7SArseny Krasnov 5155c338112SArseniy Krasnov curr_hash = 0; 5165c338112SArseniy Krasnov 5175c338112SArseniy Krasnov while (1) { 5185c338112SArseniy Krasnov ssize_t recv_size; 5195c338112SArseniy Krasnov 5205c338112SArseniy Krasnov recv_size = recvmsg(fd, &msg, 0); 5215c338112SArseniy Krasnov 5225c338112SArseniy Krasnov if (!recv_size) 5235c338112SArseniy Krasnov break; 5245c338112SArseniy Krasnov 5255c338112SArseniy Krasnov if (recv_size < 0) { 5265c338112SArseniy Krasnov perror("recvmsg"); 52741b792d7SArseny Krasnov exit(EXIT_FAILURE); 52841b792d7SArseny Krasnov } 5290e115c45SArseny Krasnov 5305c338112SArseniy Krasnov if (msg.msg_flags & MSG_EOR) 5315c338112SArseniy Krasnov curr_hash++; 5325c338112SArseniy Krasnov 5335c338112SArseniy Krasnov curr_hash += hash_djb2(msg.msg_iov[0].iov_base, recv_size); 53441b792d7SArseny Krasnov } 53541b792d7SArseny Krasnov 53641b792d7SArseny Krasnov close(fd); 5375c338112SArseniy Krasnov remote_hash = control_readulong(); 5385c338112SArseniy Krasnov 5395c338112SArseniy Krasnov if (curr_hash != remote_hash) { 5405c338112SArseniy Krasnov fprintf(stderr, "Message bounds broken\n"); 5415c338112SArseniy Krasnov exit(EXIT_FAILURE); 5425c338112SArseniy Krasnov } 54341b792d7SArseny Krasnov } 54441b792d7SArseny Krasnov 54541b792d7SArseny Krasnov #define MESSAGE_TRUNC_SZ 32 54641b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_client(const struct test_opts *opts) 54741b792d7SArseny Krasnov { 54841b792d7SArseny Krasnov int fd; 54941b792d7SArseny Krasnov char buf[MESSAGE_TRUNC_SZ]; 55041b792d7SArseny Krasnov 55141b792d7SArseny Krasnov fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 55241b792d7SArseny Krasnov if (fd < 0) { 55341b792d7SArseny Krasnov perror("connect"); 55441b792d7SArseny Krasnov exit(EXIT_FAILURE); 55541b792d7SArseny Krasnov } 55641b792d7SArseny Krasnov 55741b792d7SArseny Krasnov if (send(fd, buf, sizeof(buf), 0) != sizeof(buf)) { 55841b792d7SArseny Krasnov perror("send failed"); 55941b792d7SArseny Krasnov exit(EXIT_FAILURE); 56041b792d7SArseny Krasnov } 56141b792d7SArseny Krasnov 56241b792d7SArseny Krasnov control_writeln("SENDDONE"); 56341b792d7SArseny Krasnov close(fd); 56441b792d7SArseny Krasnov } 56541b792d7SArseny Krasnov 56641b792d7SArseny Krasnov static void test_seqpacket_msg_trunc_server(const struct test_opts *opts) 56741b792d7SArseny Krasnov { 56841b792d7SArseny Krasnov int fd; 56941b792d7SArseny Krasnov char buf[MESSAGE_TRUNC_SZ / 2]; 57041b792d7SArseny Krasnov struct msghdr msg = {0}; 57141b792d7SArseny Krasnov struct iovec iov = {0}; 57241b792d7SArseny Krasnov 57341b792d7SArseny Krasnov fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 57441b792d7SArseny Krasnov if (fd < 0) { 57541b792d7SArseny Krasnov perror("accept"); 57641b792d7SArseny Krasnov exit(EXIT_FAILURE); 57741b792d7SArseny Krasnov } 57841b792d7SArseny Krasnov 57941b792d7SArseny Krasnov control_expectln("SENDDONE"); 58041b792d7SArseny Krasnov iov.iov_base = buf; 58141b792d7SArseny Krasnov iov.iov_len = sizeof(buf); 58241b792d7SArseny Krasnov msg.msg_iov = &iov; 58341b792d7SArseny Krasnov msg.msg_iovlen = 1; 58441b792d7SArseny Krasnov 58541b792d7SArseny Krasnov ssize_t ret = recvmsg(fd, &msg, MSG_TRUNC); 58641b792d7SArseny Krasnov 58741b792d7SArseny Krasnov if (ret != MESSAGE_TRUNC_SZ) { 58841b792d7SArseny Krasnov printf("%zi\n", ret); 58941b792d7SArseny Krasnov perror("MSG_TRUNC doesn't work"); 59041b792d7SArseny Krasnov exit(EXIT_FAILURE); 59141b792d7SArseny Krasnov } 59241b792d7SArseny Krasnov 59341b792d7SArseny Krasnov if (!(msg.msg_flags & MSG_TRUNC)) { 59441b792d7SArseny Krasnov fprintf(stderr, "MSG_TRUNC expected\n"); 59541b792d7SArseny Krasnov exit(EXIT_FAILURE); 59641b792d7SArseny Krasnov } 59741b792d7SArseny Krasnov 59841b792d7SArseny Krasnov close(fd); 59941b792d7SArseny Krasnov } 60041b792d7SArseny Krasnov 601efb3719fSKrasnov Arseniy Vladimirovich static time_t current_nsec(void) 602efb3719fSKrasnov Arseniy Vladimirovich { 603efb3719fSKrasnov Arseniy Vladimirovich struct timespec ts; 604efb3719fSKrasnov Arseniy Vladimirovich 605efb3719fSKrasnov Arseniy Vladimirovich if (clock_gettime(CLOCK_REALTIME, &ts)) { 606efb3719fSKrasnov Arseniy Vladimirovich perror("clock_gettime(3) failed"); 607efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 608efb3719fSKrasnov Arseniy Vladimirovich } 609efb3719fSKrasnov Arseniy Vladimirovich 610efb3719fSKrasnov Arseniy Vladimirovich return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec; 611efb3719fSKrasnov Arseniy Vladimirovich } 612efb3719fSKrasnov Arseniy Vladimirovich 613efb3719fSKrasnov Arseniy Vladimirovich #define RCVTIMEO_TIMEOUT_SEC 1 614efb3719fSKrasnov Arseniy Vladimirovich #define READ_OVERHEAD_NSEC 250000000 /* 0.25 sec */ 615efb3719fSKrasnov Arseniy Vladimirovich 616efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_client(const struct test_opts *opts) 617efb3719fSKrasnov Arseniy Vladimirovich { 618efb3719fSKrasnov Arseniy Vladimirovich int fd; 619efb3719fSKrasnov Arseniy Vladimirovich struct timeval tv; 620efb3719fSKrasnov Arseniy Vladimirovich char dummy; 621efb3719fSKrasnov Arseniy Vladimirovich time_t read_enter_ns; 622efb3719fSKrasnov Arseniy Vladimirovich time_t read_overhead_ns; 623efb3719fSKrasnov Arseniy Vladimirovich 624efb3719fSKrasnov Arseniy Vladimirovich fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 625efb3719fSKrasnov Arseniy Vladimirovich if (fd < 0) { 626efb3719fSKrasnov Arseniy Vladimirovich perror("connect"); 627efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 628efb3719fSKrasnov Arseniy Vladimirovich } 629efb3719fSKrasnov Arseniy Vladimirovich 630efb3719fSKrasnov Arseniy Vladimirovich tv.tv_sec = RCVTIMEO_TIMEOUT_SEC; 631efb3719fSKrasnov Arseniy Vladimirovich tv.tv_usec = 0; 632efb3719fSKrasnov Arseniy Vladimirovich 633efb3719fSKrasnov Arseniy Vladimirovich if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) { 6345c338112SArseniy Krasnov perror("setsockopt(SO_RCVTIMEO)"); 635efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 636efb3719fSKrasnov Arseniy Vladimirovich } 637efb3719fSKrasnov Arseniy Vladimirovich 638efb3719fSKrasnov Arseniy Vladimirovich read_enter_ns = current_nsec(); 639efb3719fSKrasnov Arseniy Vladimirovich 640efb3719fSKrasnov Arseniy Vladimirovich if (read(fd, &dummy, sizeof(dummy)) != -1) { 641efb3719fSKrasnov Arseniy Vladimirovich fprintf(stderr, 642efb3719fSKrasnov Arseniy Vladimirovich "expected 'dummy' read(2) failure\n"); 643efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 644efb3719fSKrasnov Arseniy Vladimirovich } 645efb3719fSKrasnov Arseniy Vladimirovich 646efb3719fSKrasnov Arseniy Vladimirovich if (errno != EAGAIN) { 647efb3719fSKrasnov Arseniy Vladimirovich perror("EAGAIN expected"); 648efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 649efb3719fSKrasnov Arseniy Vladimirovich } 650efb3719fSKrasnov Arseniy Vladimirovich 651efb3719fSKrasnov Arseniy Vladimirovich read_overhead_ns = current_nsec() - read_enter_ns - 652efb3719fSKrasnov Arseniy Vladimirovich 1000000000ULL * RCVTIMEO_TIMEOUT_SEC; 653efb3719fSKrasnov Arseniy Vladimirovich 654efb3719fSKrasnov Arseniy Vladimirovich if (read_overhead_ns > READ_OVERHEAD_NSEC) { 655efb3719fSKrasnov Arseniy Vladimirovich fprintf(stderr, 656efb3719fSKrasnov Arseniy Vladimirovich "too much time in read(2), %lu > %i ns\n", 657efb3719fSKrasnov Arseniy Vladimirovich read_overhead_ns, READ_OVERHEAD_NSEC); 658efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 659efb3719fSKrasnov Arseniy Vladimirovich } 660efb3719fSKrasnov Arseniy Vladimirovich 661efb3719fSKrasnov Arseniy Vladimirovich control_writeln("WAITDONE"); 662efb3719fSKrasnov Arseniy Vladimirovich close(fd); 663efb3719fSKrasnov Arseniy Vladimirovich } 664efb3719fSKrasnov Arseniy Vladimirovich 665efb3719fSKrasnov Arseniy Vladimirovich static void test_seqpacket_timeout_server(const struct test_opts *opts) 666efb3719fSKrasnov Arseniy Vladimirovich { 667efb3719fSKrasnov Arseniy Vladimirovich int fd; 668efb3719fSKrasnov Arseniy Vladimirovich 669efb3719fSKrasnov Arseniy Vladimirovich fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 670efb3719fSKrasnov Arseniy Vladimirovich if (fd < 0) { 671efb3719fSKrasnov Arseniy Vladimirovich perror("accept"); 672efb3719fSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 673efb3719fSKrasnov Arseniy Vladimirovich } 674efb3719fSKrasnov Arseniy Vladimirovich 675efb3719fSKrasnov Arseniy Vladimirovich control_expectln("WAITDONE"); 676efb3719fSKrasnov Arseniy Vladimirovich close(fd); 677efb3719fSKrasnov Arseniy Vladimirovich } 678efb3719fSKrasnov Arseniy Vladimirovich 679685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_client(const struct test_opts *opts) 680685a21c3SArseniy Krasnov { 681685a21c3SArseniy Krasnov unsigned long sock_buf_size; 682685a21c3SArseniy Krasnov ssize_t send_size; 683685a21c3SArseniy Krasnov socklen_t len; 684685a21c3SArseniy Krasnov void *data; 685685a21c3SArseniy Krasnov int fd; 686685a21c3SArseniy Krasnov 687685a21c3SArseniy Krasnov len = sizeof(sock_buf_size); 688685a21c3SArseniy Krasnov 689685a21c3SArseniy Krasnov fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 690685a21c3SArseniy Krasnov if (fd < 0) { 691685a21c3SArseniy Krasnov perror("connect"); 692685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 693685a21c3SArseniy Krasnov } 694685a21c3SArseniy Krasnov 695685a21c3SArseniy Krasnov if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, 696685a21c3SArseniy Krasnov &sock_buf_size, &len)) { 697685a21c3SArseniy Krasnov perror("getsockopt"); 698685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 699685a21c3SArseniy Krasnov } 700685a21c3SArseniy Krasnov 701685a21c3SArseniy Krasnov sock_buf_size++; 702685a21c3SArseniy Krasnov 703685a21c3SArseniy Krasnov data = malloc(sock_buf_size); 704685a21c3SArseniy Krasnov if (!data) { 705685a21c3SArseniy Krasnov perror("malloc"); 706685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 707685a21c3SArseniy Krasnov } 708685a21c3SArseniy Krasnov 709685a21c3SArseniy Krasnov send_size = send(fd, data, sock_buf_size, 0); 710685a21c3SArseniy Krasnov if (send_size != -1) { 711685a21c3SArseniy Krasnov fprintf(stderr, "expected 'send(2)' failure, got %zi\n", 712685a21c3SArseniy Krasnov send_size); 713685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 714685a21c3SArseniy Krasnov } 715685a21c3SArseniy Krasnov 716685a21c3SArseniy Krasnov if (errno != EMSGSIZE) { 717685a21c3SArseniy Krasnov fprintf(stderr, "expected EMSGSIZE in 'errno', got %i\n", 718685a21c3SArseniy Krasnov errno); 719685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 720685a21c3SArseniy Krasnov } 721685a21c3SArseniy Krasnov 722685a21c3SArseniy Krasnov control_writeln("CLISENT"); 723685a21c3SArseniy Krasnov 724685a21c3SArseniy Krasnov free(data); 725685a21c3SArseniy Krasnov close(fd); 726685a21c3SArseniy Krasnov } 727685a21c3SArseniy Krasnov 728685a21c3SArseniy Krasnov static void test_seqpacket_bigmsg_server(const struct test_opts *opts) 729685a21c3SArseniy Krasnov { 730685a21c3SArseniy Krasnov int fd; 731685a21c3SArseniy Krasnov 732685a21c3SArseniy Krasnov fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 733685a21c3SArseniy Krasnov if (fd < 0) { 734685a21c3SArseniy Krasnov perror("accept"); 735685a21c3SArseniy Krasnov exit(EXIT_FAILURE); 736685a21c3SArseniy Krasnov } 737685a21c3SArseniy Krasnov 738685a21c3SArseniy Krasnov control_expectln("CLISENT"); 739685a21c3SArseniy Krasnov 740685a21c3SArseniy Krasnov close(fd); 741685a21c3SArseniy Krasnov } 742685a21c3SArseniy Krasnov 743e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_1 'a' 744e89600ebSKrasnov Arseniy Vladimirovich #define BUF_PATTERN_2 'b' 745e89600ebSKrasnov Arseniy Vladimirovich 746e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_client(const struct test_opts *opts) 747e89600ebSKrasnov Arseniy Vladimirovich { 748e89600ebSKrasnov Arseniy Vladimirovich int fd; 749e89600ebSKrasnov Arseniy Vladimirovich unsigned char *buf1; 750e89600ebSKrasnov Arseniy Vladimirovich unsigned char *buf2; 751e89600ebSKrasnov Arseniy Vladimirovich int buf_size = getpagesize() * 3; 752e89600ebSKrasnov Arseniy Vladimirovich 753e89600ebSKrasnov Arseniy Vladimirovich fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 754e89600ebSKrasnov Arseniy Vladimirovich if (fd < 0) { 755e89600ebSKrasnov Arseniy Vladimirovich perror("connect"); 756e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 757e89600ebSKrasnov Arseniy Vladimirovich } 758e89600ebSKrasnov Arseniy Vladimirovich 759e89600ebSKrasnov Arseniy Vladimirovich buf1 = malloc(buf_size); 760e89600ebSKrasnov Arseniy Vladimirovich if (!buf1) { 761e89600ebSKrasnov Arseniy Vladimirovich perror("'malloc()' for 'buf1'"); 762e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 763e89600ebSKrasnov Arseniy Vladimirovich } 764e89600ebSKrasnov Arseniy Vladimirovich 765e89600ebSKrasnov Arseniy Vladimirovich buf2 = malloc(buf_size); 766e89600ebSKrasnov Arseniy Vladimirovich if (!buf2) { 767e89600ebSKrasnov Arseniy Vladimirovich perror("'malloc()' for 'buf2'"); 768e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 769e89600ebSKrasnov Arseniy Vladimirovich } 770e89600ebSKrasnov Arseniy Vladimirovich 771e89600ebSKrasnov Arseniy Vladimirovich memset(buf1, BUF_PATTERN_1, buf_size); 772e89600ebSKrasnov Arseniy Vladimirovich memset(buf2, BUF_PATTERN_2, buf_size); 773e89600ebSKrasnov Arseniy Vladimirovich 774e89600ebSKrasnov Arseniy Vladimirovich if (send(fd, buf1, buf_size, 0) != buf_size) { 775e89600ebSKrasnov Arseniy Vladimirovich perror("send failed"); 776e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 777e89600ebSKrasnov Arseniy Vladimirovich } 778e89600ebSKrasnov Arseniy Vladimirovich 779e89600ebSKrasnov Arseniy Vladimirovich if (send(fd, buf2, buf_size, 0) != buf_size) { 780e89600ebSKrasnov Arseniy Vladimirovich perror("send failed"); 781e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 782e89600ebSKrasnov Arseniy Vladimirovich } 783e89600ebSKrasnov Arseniy Vladimirovich 784e89600ebSKrasnov Arseniy Vladimirovich close(fd); 785e89600ebSKrasnov Arseniy Vladimirovich } 786e89600ebSKrasnov Arseniy Vladimirovich 787e89600ebSKrasnov Arseniy Vladimirovich static void test_seqpacket_invalid_rec_buffer_server(const struct test_opts *opts) 788e89600ebSKrasnov Arseniy Vladimirovich { 789e89600ebSKrasnov Arseniy Vladimirovich int fd; 790e89600ebSKrasnov Arseniy Vladimirovich unsigned char *broken_buf; 791e89600ebSKrasnov Arseniy Vladimirovich unsigned char *valid_buf; 792e89600ebSKrasnov Arseniy Vladimirovich int page_size = getpagesize(); 793e89600ebSKrasnov Arseniy Vladimirovich int buf_size = page_size * 3; 794e89600ebSKrasnov Arseniy Vladimirovich ssize_t res; 795e89600ebSKrasnov Arseniy Vladimirovich int prot = PROT_READ | PROT_WRITE; 796e89600ebSKrasnov Arseniy Vladimirovich int flags = MAP_PRIVATE | MAP_ANONYMOUS; 797e89600ebSKrasnov Arseniy Vladimirovich int i; 798e89600ebSKrasnov Arseniy Vladimirovich 799e89600ebSKrasnov Arseniy Vladimirovich fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 800e89600ebSKrasnov Arseniy Vladimirovich if (fd < 0) { 801e89600ebSKrasnov Arseniy Vladimirovich perror("accept"); 802e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 803e89600ebSKrasnov Arseniy Vladimirovich } 804e89600ebSKrasnov Arseniy Vladimirovich 805e89600ebSKrasnov Arseniy Vladimirovich /* Setup first buffer. */ 806e89600ebSKrasnov Arseniy Vladimirovich broken_buf = mmap(NULL, buf_size, prot, flags, -1, 0); 807e89600ebSKrasnov Arseniy Vladimirovich if (broken_buf == MAP_FAILED) { 808e89600ebSKrasnov Arseniy Vladimirovich perror("mmap for 'broken_buf'"); 809e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 810e89600ebSKrasnov Arseniy Vladimirovich } 811e89600ebSKrasnov Arseniy Vladimirovich 812e89600ebSKrasnov Arseniy Vladimirovich /* Unmap "hole" in buffer. */ 813e89600ebSKrasnov Arseniy Vladimirovich if (munmap(broken_buf + page_size, page_size)) { 814e89600ebSKrasnov Arseniy Vladimirovich perror("'broken_buf' setup"); 815e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 816e89600ebSKrasnov Arseniy Vladimirovich } 817e89600ebSKrasnov Arseniy Vladimirovich 818e89600ebSKrasnov Arseniy Vladimirovich valid_buf = mmap(NULL, buf_size, prot, flags, -1, 0); 819e89600ebSKrasnov Arseniy Vladimirovich if (valid_buf == MAP_FAILED) { 820e89600ebSKrasnov Arseniy Vladimirovich perror("mmap for 'valid_buf'"); 821e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 822e89600ebSKrasnov Arseniy Vladimirovich } 823e89600ebSKrasnov Arseniy Vladimirovich 824e89600ebSKrasnov Arseniy Vladimirovich /* Try to fill buffer with unmapped middle. */ 825e89600ebSKrasnov Arseniy Vladimirovich res = read(fd, broken_buf, buf_size); 826e89600ebSKrasnov Arseniy Vladimirovich if (res != -1) { 827e89600ebSKrasnov Arseniy Vladimirovich fprintf(stderr, 828e89600ebSKrasnov Arseniy Vladimirovich "expected 'broken_buf' read(2) failure, got %zi\n", 829e89600ebSKrasnov Arseniy Vladimirovich res); 830e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 831e89600ebSKrasnov Arseniy Vladimirovich } 832e89600ebSKrasnov Arseniy Vladimirovich 833b5d54eb5SArseniy Krasnov if (errno != EFAULT) { 834e89600ebSKrasnov Arseniy Vladimirovich perror("unexpected errno of 'broken_buf'"); 835e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 836e89600ebSKrasnov Arseniy Vladimirovich } 837e89600ebSKrasnov Arseniy Vladimirovich 838e89600ebSKrasnov Arseniy Vladimirovich /* Try to fill valid buffer. */ 839e89600ebSKrasnov Arseniy Vladimirovich res = read(fd, valid_buf, buf_size); 840e89600ebSKrasnov Arseniy Vladimirovich if (res < 0) { 841e89600ebSKrasnov Arseniy Vladimirovich perror("unexpected 'valid_buf' read(2) failure"); 842e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 843e89600ebSKrasnov Arseniy Vladimirovich } 844e89600ebSKrasnov Arseniy Vladimirovich 845e89600ebSKrasnov Arseniy Vladimirovich if (res != buf_size) { 846e89600ebSKrasnov Arseniy Vladimirovich fprintf(stderr, 847e89600ebSKrasnov Arseniy Vladimirovich "invalid 'valid_buf' read(2), expected %i, got %zi\n", 848e89600ebSKrasnov Arseniy Vladimirovich buf_size, res); 849e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 850e89600ebSKrasnov Arseniy Vladimirovich } 851e89600ebSKrasnov Arseniy Vladimirovich 852e89600ebSKrasnov Arseniy Vladimirovich for (i = 0; i < buf_size; i++) { 853e89600ebSKrasnov Arseniy Vladimirovich if (valid_buf[i] != BUF_PATTERN_2) { 854e89600ebSKrasnov Arseniy Vladimirovich fprintf(stderr, 855e89600ebSKrasnov Arseniy Vladimirovich "invalid pattern for 'valid_buf' at %i, expected %hhX, got %hhX\n", 856e89600ebSKrasnov Arseniy Vladimirovich i, BUF_PATTERN_2, valid_buf[i]); 857e89600ebSKrasnov Arseniy Vladimirovich exit(EXIT_FAILURE); 858e89600ebSKrasnov Arseniy Vladimirovich } 859e89600ebSKrasnov Arseniy Vladimirovich } 860e89600ebSKrasnov Arseniy Vladimirovich 861e89600ebSKrasnov Arseniy Vladimirovich /* Unmap buffers. */ 862e89600ebSKrasnov Arseniy Vladimirovich munmap(broken_buf, page_size); 863e89600ebSKrasnov Arseniy Vladimirovich munmap(broken_buf + page_size * 2, page_size); 864e89600ebSKrasnov Arseniy Vladimirovich munmap(valid_buf, buf_size); 865e89600ebSKrasnov Arseniy Vladimirovich close(fd); 866e89600ebSKrasnov Arseniy Vladimirovich } 867e89600ebSKrasnov Arseniy Vladimirovich 868b1346338SArseniy Krasnov #define RCVLOWAT_BUF_SIZE 128 869b1346338SArseniy Krasnov 870b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_server(const struct test_opts *opts) 871b1346338SArseniy Krasnov { 872b1346338SArseniy Krasnov int fd; 873b1346338SArseniy Krasnov int i; 874b1346338SArseniy Krasnov 875b1346338SArseniy Krasnov fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 876b1346338SArseniy Krasnov if (fd < 0) { 877b1346338SArseniy Krasnov perror("accept"); 878b1346338SArseniy Krasnov exit(EXIT_FAILURE); 879b1346338SArseniy Krasnov } 880b1346338SArseniy Krasnov 881b1346338SArseniy Krasnov /* Send 1 byte. */ 882b1346338SArseniy Krasnov send_byte(fd, 1, 0); 883b1346338SArseniy Krasnov 884b1346338SArseniy Krasnov control_writeln("SRVSENT"); 885b1346338SArseniy Krasnov 886b1346338SArseniy Krasnov /* Wait until client is ready to receive rest of data. */ 887b1346338SArseniy Krasnov control_expectln("CLNSENT"); 888b1346338SArseniy Krasnov 889b1346338SArseniy Krasnov for (i = 0; i < RCVLOWAT_BUF_SIZE - 1; i++) 890b1346338SArseniy Krasnov send_byte(fd, 1, 0); 891b1346338SArseniy Krasnov 892b1346338SArseniy Krasnov /* Keep socket in active state. */ 893b1346338SArseniy Krasnov control_expectln("POLLDONE"); 894b1346338SArseniy Krasnov 895b1346338SArseniy Krasnov close(fd); 896b1346338SArseniy Krasnov } 897b1346338SArseniy Krasnov 898b1346338SArseniy Krasnov static void test_stream_poll_rcvlowat_client(const struct test_opts *opts) 899b1346338SArseniy Krasnov { 900b1346338SArseniy Krasnov unsigned long lowat_val = RCVLOWAT_BUF_SIZE; 901b1346338SArseniy Krasnov char buf[RCVLOWAT_BUF_SIZE]; 902b1346338SArseniy Krasnov struct pollfd fds; 903b1346338SArseniy Krasnov ssize_t read_res; 904b1346338SArseniy Krasnov short poll_flags; 905b1346338SArseniy Krasnov int fd; 906b1346338SArseniy Krasnov 907b1346338SArseniy Krasnov fd = vsock_stream_connect(opts->peer_cid, 1234); 908b1346338SArseniy Krasnov if (fd < 0) { 909b1346338SArseniy Krasnov perror("connect"); 910b1346338SArseniy Krasnov exit(EXIT_FAILURE); 911b1346338SArseniy Krasnov } 912b1346338SArseniy Krasnov 913b1346338SArseniy Krasnov if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, 914b1346338SArseniy Krasnov &lowat_val, sizeof(lowat_val))) { 9155c338112SArseniy Krasnov perror("setsockopt(SO_RCVLOWAT)"); 916b1346338SArseniy Krasnov exit(EXIT_FAILURE); 917b1346338SArseniy Krasnov } 918b1346338SArseniy Krasnov 919b1346338SArseniy Krasnov control_expectln("SRVSENT"); 920b1346338SArseniy Krasnov 921b1346338SArseniy Krasnov /* At this point, server sent 1 byte. */ 922b1346338SArseniy Krasnov fds.fd = fd; 923b1346338SArseniy Krasnov poll_flags = POLLIN | POLLRDNORM; 924b1346338SArseniy Krasnov fds.events = poll_flags; 925b1346338SArseniy Krasnov 926b1346338SArseniy Krasnov /* Try to wait for 1 sec. */ 927b1346338SArseniy Krasnov if (poll(&fds, 1, 1000) < 0) { 928b1346338SArseniy Krasnov perror("poll"); 929b1346338SArseniy Krasnov exit(EXIT_FAILURE); 930b1346338SArseniy Krasnov } 931b1346338SArseniy Krasnov 932b1346338SArseniy Krasnov /* poll() must return nothing. */ 933b1346338SArseniy Krasnov if (fds.revents) { 934b1346338SArseniy Krasnov fprintf(stderr, "Unexpected poll result %hx\n", 935b1346338SArseniy Krasnov fds.revents); 936b1346338SArseniy Krasnov exit(EXIT_FAILURE); 937b1346338SArseniy Krasnov } 938b1346338SArseniy Krasnov 939b1346338SArseniy Krasnov /* Tell server to send rest of data. */ 940b1346338SArseniy Krasnov control_writeln("CLNSENT"); 941b1346338SArseniy Krasnov 942b1346338SArseniy Krasnov /* Poll for data. */ 943b1346338SArseniy Krasnov if (poll(&fds, 1, 10000) < 0) { 944b1346338SArseniy Krasnov perror("poll"); 945b1346338SArseniy Krasnov exit(EXIT_FAILURE); 946b1346338SArseniy Krasnov } 947b1346338SArseniy Krasnov 948b1346338SArseniy Krasnov /* Only these two bits are expected. */ 949b1346338SArseniy Krasnov if (fds.revents != poll_flags) { 950b1346338SArseniy Krasnov fprintf(stderr, "Unexpected poll result %hx\n", 951b1346338SArseniy Krasnov fds.revents); 952b1346338SArseniy Krasnov exit(EXIT_FAILURE); 953b1346338SArseniy Krasnov } 954b1346338SArseniy Krasnov 955b1346338SArseniy Krasnov /* Use MSG_DONTWAIT, if call is going to wait, EAGAIN 956b1346338SArseniy Krasnov * will be returned. 957b1346338SArseniy Krasnov */ 958b1346338SArseniy Krasnov read_res = recv(fd, buf, sizeof(buf), MSG_DONTWAIT); 959b1346338SArseniy Krasnov if (read_res != RCVLOWAT_BUF_SIZE) { 960b1346338SArseniy Krasnov fprintf(stderr, "Unexpected recv result %zi\n", 961b1346338SArseniy Krasnov read_res); 962b1346338SArseniy Krasnov exit(EXIT_FAILURE); 963b1346338SArseniy Krasnov } 964b1346338SArseniy Krasnov 965b1346338SArseniy Krasnov control_writeln("POLLDONE"); 966b1346338SArseniy Krasnov 967b1346338SArseniy Krasnov close(fd); 968b1346338SArseniy Krasnov } 969b1346338SArseniy Krasnov 9707e699d2aSArseniy Krasnov #define INV_BUF_TEST_DATA_LEN 512 9717e699d2aSArseniy Krasnov 9727e699d2aSArseniy Krasnov static void test_inv_buf_client(const struct test_opts *opts, bool stream) 9737e699d2aSArseniy Krasnov { 9747e699d2aSArseniy Krasnov unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; 9757e699d2aSArseniy Krasnov ssize_t ret; 9767e699d2aSArseniy Krasnov int fd; 9777e699d2aSArseniy Krasnov 9787e699d2aSArseniy Krasnov if (stream) 9797e699d2aSArseniy Krasnov fd = vsock_stream_connect(opts->peer_cid, 1234); 9807e699d2aSArseniy Krasnov else 9817e699d2aSArseniy Krasnov fd = vsock_seqpacket_connect(opts->peer_cid, 1234); 9827e699d2aSArseniy Krasnov 9837e699d2aSArseniy Krasnov if (fd < 0) { 9847e699d2aSArseniy Krasnov perror("connect"); 9857e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 9867e699d2aSArseniy Krasnov } 9877e699d2aSArseniy Krasnov 9887e699d2aSArseniy Krasnov control_expectln("SENDDONE"); 9897e699d2aSArseniy Krasnov 9907e699d2aSArseniy Krasnov /* Use invalid buffer here. */ 9917e699d2aSArseniy Krasnov ret = recv(fd, NULL, sizeof(data), 0); 9927e699d2aSArseniy Krasnov if (ret != -1) { 9937e699d2aSArseniy Krasnov fprintf(stderr, "expected recv(2) failure, got %zi\n", ret); 9947e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 9957e699d2aSArseniy Krasnov } 9967e699d2aSArseniy Krasnov 997b5d54eb5SArseniy Krasnov if (errno != EFAULT) { 9987e699d2aSArseniy Krasnov fprintf(stderr, "unexpected recv(2) errno %d\n", errno); 9997e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 10007e699d2aSArseniy Krasnov } 10017e699d2aSArseniy Krasnov 10027e699d2aSArseniy Krasnov ret = recv(fd, data, sizeof(data), MSG_DONTWAIT); 10037e699d2aSArseniy Krasnov 10047e699d2aSArseniy Krasnov if (stream) { 10057e699d2aSArseniy Krasnov /* For SOCK_STREAM we must continue reading. */ 10067e699d2aSArseniy Krasnov if (ret != sizeof(data)) { 10077e699d2aSArseniy Krasnov fprintf(stderr, "expected recv(2) success, got %zi\n", ret); 10087e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 10097e699d2aSArseniy Krasnov } 10107e699d2aSArseniy Krasnov /* Don't check errno in case of success. */ 10117e699d2aSArseniy Krasnov } else { 10127e699d2aSArseniy Krasnov /* For SOCK_SEQPACKET socket's queue must be empty. */ 10137e699d2aSArseniy Krasnov if (ret != -1) { 10147e699d2aSArseniy Krasnov fprintf(stderr, "expected recv(2) failure, got %zi\n", ret); 10157e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 10167e699d2aSArseniy Krasnov } 10177e699d2aSArseniy Krasnov 10187e699d2aSArseniy Krasnov if (errno != EAGAIN) { 10197e699d2aSArseniy Krasnov fprintf(stderr, "unexpected recv(2) errno %d\n", errno); 10207e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 10217e699d2aSArseniy Krasnov } 10227e699d2aSArseniy Krasnov } 10237e699d2aSArseniy Krasnov 10247e699d2aSArseniy Krasnov control_writeln("DONE"); 10257e699d2aSArseniy Krasnov 10267e699d2aSArseniy Krasnov close(fd); 10277e699d2aSArseniy Krasnov } 10287e699d2aSArseniy Krasnov 10297e699d2aSArseniy Krasnov static void test_inv_buf_server(const struct test_opts *opts, bool stream) 10307e699d2aSArseniy Krasnov { 10317e699d2aSArseniy Krasnov unsigned char data[INV_BUF_TEST_DATA_LEN] = {0}; 10327e699d2aSArseniy Krasnov ssize_t res; 10337e699d2aSArseniy Krasnov int fd; 10347e699d2aSArseniy Krasnov 10357e699d2aSArseniy Krasnov if (stream) 10367e699d2aSArseniy Krasnov fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 10377e699d2aSArseniy Krasnov else 10387e699d2aSArseniy Krasnov fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL); 10397e699d2aSArseniy Krasnov 10407e699d2aSArseniy Krasnov if (fd < 0) { 10417e699d2aSArseniy Krasnov perror("accept"); 10427e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 10437e699d2aSArseniy Krasnov } 10447e699d2aSArseniy Krasnov 10457e699d2aSArseniy Krasnov res = send(fd, data, sizeof(data), 0); 10467e699d2aSArseniy Krasnov if (res != sizeof(data)) { 10477e699d2aSArseniy Krasnov fprintf(stderr, "unexpected send(2) result %zi\n", res); 10487e699d2aSArseniy Krasnov exit(EXIT_FAILURE); 10497e699d2aSArseniy Krasnov } 10507e699d2aSArseniy Krasnov 10517e699d2aSArseniy Krasnov control_writeln("SENDDONE"); 10527e699d2aSArseniy Krasnov 10537e699d2aSArseniy Krasnov control_expectln("DONE"); 10547e699d2aSArseniy Krasnov 10557e699d2aSArseniy Krasnov close(fd); 10567e699d2aSArseniy Krasnov } 10577e699d2aSArseniy Krasnov 10587e699d2aSArseniy Krasnov static void test_stream_inv_buf_client(const struct test_opts *opts) 10597e699d2aSArseniy Krasnov { 10607e699d2aSArseniy Krasnov test_inv_buf_client(opts, true); 10617e699d2aSArseniy Krasnov } 10627e699d2aSArseniy Krasnov 10637e699d2aSArseniy Krasnov static void test_stream_inv_buf_server(const struct test_opts *opts) 10647e699d2aSArseniy Krasnov { 10657e699d2aSArseniy Krasnov test_inv_buf_server(opts, true); 10667e699d2aSArseniy Krasnov } 10677e699d2aSArseniy Krasnov 10687e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_client(const struct test_opts *opts) 10697e699d2aSArseniy Krasnov { 10707e699d2aSArseniy Krasnov test_inv_buf_client(opts, false); 10717e699d2aSArseniy Krasnov } 10727e699d2aSArseniy Krasnov 10737e699d2aSArseniy Krasnov static void test_seqpacket_inv_buf_server(const struct test_opts *opts) 10747e699d2aSArseniy Krasnov { 10757e699d2aSArseniy Krasnov test_inv_buf_server(opts, false); 10767e699d2aSArseniy Krasnov } 10777e699d2aSArseniy Krasnov 107825209a32SArseniy Krasnov #define HELLO_STR "HELLO" 107925209a32SArseniy Krasnov #define WORLD_STR "WORLD" 108025209a32SArseniy Krasnov 108125209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_client(const struct test_opts *opts) 108225209a32SArseniy Krasnov { 108325209a32SArseniy Krasnov ssize_t res; 108425209a32SArseniy Krasnov int fd; 108525209a32SArseniy Krasnov 108625209a32SArseniy Krasnov fd = vsock_stream_connect(opts->peer_cid, 1234); 108725209a32SArseniy Krasnov if (fd < 0) { 108825209a32SArseniy Krasnov perror("connect"); 108925209a32SArseniy Krasnov exit(EXIT_FAILURE); 109025209a32SArseniy Krasnov } 109125209a32SArseniy Krasnov 109225209a32SArseniy Krasnov /* Send first skbuff. */ 109325209a32SArseniy Krasnov res = send(fd, HELLO_STR, strlen(HELLO_STR), 0); 109425209a32SArseniy Krasnov if (res != strlen(HELLO_STR)) { 109525209a32SArseniy Krasnov fprintf(stderr, "unexpected send(2) result %zi\n", res); 109625209a32SArseniy Krasnov exit(EXIT_FAILURE); 109725209a32SArseniy Krasnov } 109825209a32SArseniy Krasnov 109925209a32SArseniy Krasnov control_writeln("SEND0"); 110025209a32SArseniy Krasnov /* Peer reads part of first skbuff. */ 110125209a32SArseniy Krasnov control_expectln("REPLY0"); 110225209a32SArseniy Krasnov 110325209a32SArseniy Krasnov /* Send second skbuff, it will be appended to the first. */ 110425209a32SArseniy Krasnov res = send(fd, WORLD_STR, strlen(WORLD_STR), 0); 110525209a32SArseniy Krasnov if (res != strlen(WORLD_STR)) { 110625209a32SArseniy Krasnov fprintf(stderr, "unexpected send(2) result %zi\n", res); 110725209a32SArseniy Krasnov exit(EXIT_FAILURE); 110825209a32SArseniy Krasnov } 110925209a32SArseniy Krasnov 111025209a32SArseniy Krasnov control_writeln("SEND1"); 111125209a32SArseniy Krasnov /* Peer reads merged skbuff packet. */ 111225209a32SArseniy Krasnov control_expectln("REPLY1"); 111325209a32SArseniy Krasnov 111425209a32SArseniy Krasnov close(fd); 111525209a32SArseniy Krasnov } 111625209a32SArseniy Krasnov 111725209a32SArseniy Krasnov static void test_stream_virtio_skb_merge_server(const struct test_opts *opts) 111825209a32SArseniy Krasnov { 111925209a32SArseniy Krasnov unsigned char buf[64]; 112025209a32SArseniy Krasnov ssize_t res; 112125209a32SArseniy Krasnov int fd; 112225209a32SArseniy Krasnov 112325209a32SArseniy Krasnov fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL); 112425209a32SArseniy Krasnov if (fd < 0) { 112525209a32SArseniy Krasnov perror("accept"); 112625209a32SArseniy Krasnov exit(EXIT_FAILURE); 112725209a32SArseniy Krasnov } 112825209a32SArseniy Krasnov 112925209a32SArseniy Krasnov control_expectln("SEND0"); 113025209a32SArseniy Krasnov 113125209a32SArseniy Krasnov /* Read skbuff partially. */ 113225209a32SArseniy Krasnov res = recv(fd, buf, 2, 0); 113325209a32SArseniy Krasnov if (res != 2) { 113425209a32SArseniy Krasnov fprintf(stderr, "expected recv(2) returns 2 bytes, got %zi\n", res); 113525209a32SArseniy Krasnov exit(EXIT_FAILURE); 113625209a32SArseniy Krasnov } 113725209a32SArseniy Krasnov 113825209a32SArseniy Krasnov control_writeln("REPLY0"); 113925209a32SArseniy Krasnov control_expectln("SEND1"); 114025209a32SArseniy Krasnov 114125209a32SArseniy Krasnov res = recv(fd, buf + 2, sizeof(buf) - 2, 0); 114225209a32SArseniy Krasnov if (res != 8) { 114325209a32SArseniy Krasnov fprintf(stderr, "expected recv(2) returns 8 bytes, got %zi\n", res); 114425209a32SArseniy Krasnov exit(EXIT_FAILURE); 114525209a32SArseniy Krasnov } 114625209a32SArseniy Krasnov 114725209a32SArseniy Krasnov res = recv(fd, buf, sizeof(buf) - 8 - 2, MSG_DONTWAIT); 114825209a32SArseniy Krasnov if (res != -1) { 114925209a32SArseniy Krasnov fprintf(stderr, "expected recv(2) failure, got %zi\n", res); 115025209a32SArseniy Krasnov exit(EXIT_FAILURE); 115125209a32SArseniy Krasnov } 115225209a32SArseniy Krasnov 115325209a32SArseniy Krasnov if (memcmp(buf, HELLO_STR WORLD_STR, strlen(HELLO_STR WORLD_STR))) { 115425209a32SArseniy Krasnov fprintf(stderr, "pattern mismatch\n"); 115525209a32SArseniy Krasnov exit(EXIT_FAILURE); 115625209a32SArseniy Krasnov } 115725209a32SArseniy Krasnov 115825209a32SArseniy Krasnov control_writeln("REPLY1"); 115925209a32SArseniy Krasnov 116025209a32SArseniy Krasnov close(fd); 116125209a32SArseniy Krasnov } 116225209a32SArseniy Krasnov 1163*8a0697f2SArseniy Krasnov static void test_seqpacket_msg_peek_client(const struct test_opts *opts) 1164*8a0697f2SArseniy Krasnov { 1165*8a0697f2SArseniy Krasnov return test_msg_peek_client(opts, true); 1166*8a0697f2SArseniy Krasnov } 1167*8a0697f2SArseniy Krasnov 1168*8a0697f2SArseniy Krasnov static void test_seqpacket_msg_peek_server(const struct test_opts *opts) 1169*8a0697f2SArseniy Krasnov { 1170*8a0697f2SArseniy Krasnov return test_msg_peek_server(opts, true); 1171*8a0697f2SArseniy Krasnov } 1172*8a0697f2SArseniy Krasnov 1173cdbcc18dSStefan Hajnoczi static struct test_case test_cases[] = { 1174cdbcc18dSStefan Hajnoczi { 1175cdbcc18dSStefan Hajnoczi .name = "SOCK_STREAM connection reset", 1176cdbcc18dSStefan Hajnoczi .run_client = test_stream_connection_reset, 1177cdbcc18dSStefan Hajnoczi }, 1178cdbcc18dSStefan Hajnoczi { 11799de9f7d1SSebastien Boeuf .name = "SOCK_STREAM bind only", 11809de9f7d1SSebastien Boeuf .run_client = test_stream_bind_only_client, 11819de9f7d1SSebastien Boeuf .run_server = test_stream_bind_only_server, 11829de9f7d1SSebastien Boeuf }, 11839de9f7d1SSebastien Boeuf { 1184cdbcc18dSStefan Hajnoczi .name = "SOCK_STREAM client close", 1185cdbcc18dSStefan Hajnoczi .run_client = test_stream_client_close_client, 1186cdbcc18dSStefan Hajnoczi .run_server = test_stream_client_close_server, 1187cdbcc18dSStefan Hajnoczi }, 1188cdbcc18dSStefan Hajnoczi { 1189cdbcc18dSStefan Hajnoczi .name = "SOCK_STREAM server close", 1190cdbcc18dSStefan Hajnoczi .run_client = test_stream_server_close_client, 1191cdbcc18dSStefan Hajnoczi .run_server = test_stream_server_close_server, 1192cdbcc18dSStefan Hajnoczi }, 1193cdbcc18dSStefan Hajnoczi { 1194cdbcc18dSStefan Hajnoczi .name = "SOCK_STREAM multiple connections", 1195cdbcc18dSStefan Hajnoczi .run_client = test_stream_multiconn_client, 1196cdbcc18dSStefan Hajnoczi .run_server = test_stream_multiconn_server, 1197cdbcc18dSStefan Hajnoczi }, 1198d6269a93SStefano Garzarella { 1199d6269a93SStefano Garzarella .name = "SOCK_STREAM MSG_PEEK", 1200d6269a93SStefano Garzarella .run_client = test_stream_msg_peek_client, 1201d6269a93SStefano Garzarella .run_server = test_stream_msg_peek_server, 1202d6269a93SStefano Garzarella }, 120341b792d7SArseny Krasnov { 120441b792d7SArseny Krasnov .name = "SOCK_SEQPACKET msg bounds", 120541b792d7SArseny Krasnov .run_client = test_seqpacket_msg_bounds_client, 120641b792d7SArseny Krasnov .run_server = test_seqpacket_msg_bounds_server, 120741b792d7SArseny Krasnov }, 120841b792d7SArseny Krasnov { 120941b792d7SArseny Krasnov .name = "SOCK_SEQPACKET MSG_TRUNC flag", 121041b792d7SArseny Krasnov .run_client = test_seqpacket_msg_trunc_client, 121141b792d7SArseny Krasnov .run_server = test_seqpacket_msg_trunc_server, 121241b792d7SArseny Krasnov }, 1213efb3719fSKrasnov Arseniy Vladimirovich { 1214efb3719fSKrasnov Arseniy Vladimirovich .name = "SOCK_SEQPACKET timeout", 1215efb3719fSKrasnov Arseniy Vladimirovich .run_client = test_seqpacket_timeout_client, 1216efb3719fSKrasnov Arseniy Vladimirovich .run_server = test_seqpacket_timeout_server, 1217efb3719fSKrasnov Arseniy Vladimirovich }, 1218e89600ebSKrasnov Arseniy Vladimirovich { 1219e89600ebSKrasnov Arseniy Vladimirovich .name = "SOCK_SEQPACKET invalid receive buffer", 1220e89600ebSKrasnov Arseniy Vladimirovich .run_client = test_seqpacket_invalid_rec_buffer_client, 1221e89600ebSKrasnov Arseniy Vladimirovich .run_server = test_seqpacket_invalid_rec_buffer_server, 1222e89600ebSKrasnov Arseniy Vladimirovich }, 1223b1346338SArseniy Krasnov { 1224b1346338SArseniy Krasnov .name = "SOCK_STREAM poll() + SO_RCVLOWAT", 1225b1346338SArseniy Krasnov .run_client = test_stream_poll_rcvlowat_client, 1226b1346338SArseniy Krasnov .run_server = test_stream_poll_rcvlowat_server, 1227b1346338SArseniy Krasnov }, 1228685a21c3SArseniy Krasnov { 1229685a21c3SArseniy Krasnov .name = "SOCK_SEQPACKET big message", 1230685a21c3SArseniy Krasnov .run_client = test_seqpacket_bigmsg_client, 1231685a21c3SArseniy Krasnov .run_server = test_seqpacket_bigmsg_server, 1232685a21c3SArseniy Krasnov }, 12337e699d2aSArseniy Krasnov { 12347e699d2aSArseniy Krasnov .name = "SOCK_STREAM test invalid buffer", 12357e699d2aSArseniy Krasnov .run_client = test_stream_inv_buf_client, 12367e699d2aSArseniy Krasnov .run_server = test_stream_inv_buf_server, 12377e699d2aSArseniy Krasnov }, 12387e699d2aSArseniy Krasnov { 12397e699d2aSArseniy Krasnov .name = "SOCK_SEQPACKET test invalid buffer", 12407e699d2aSArseniy Krasnov .run_client = test_seqpacket_inv_buf_client, 12417e699d2aSArseniy Krasnov .run_server = test_seqpacket_inv_buf_server, 12427e699d2aSArseniy Krasnov }, 124325209a32SArseniy Krasnov { 124425209a32SArseniy Krasnov .name = "SOCK_STREAM virtio skb merge", 124525209a32SArseniy Krasnov .run_client = test_stream_virtio_skb_merge_client, 124625209a32SArseniy Krasnov .run_server = test_stream_virtio_skb_merge_server, 124725209a32SArseniy Krasnov }, 1248*8a0697f2SArseniy Krasnov { 1249*8a0697f2SArseniy Krasnov .name = "SOCK_SEQPACKET MSG_PEEK", 1250*8a0697f2SArseniy Krasnov .run_client = test_seqpacket_msg_peek_client, 1251*8a0697f2SArseniy Krasnov .run_server = test_seqpacket_msg_peek_server, 1252*8a0697f2SArseniy Krasnov }, 1253cdbcc18dSStefan Hajnoczi {}, 1254cdbcc18dSStefan Hajnoczi }; 1255cdbcc18dSStefan Hajnoczi 1256cdbcc18dSStefan Hajnoczi static const char optstring[] = ""; 1257cdbcc18dSStefan Hajnoczi static const struct option longopts[] = { 1258cdbcc18dSStefan Hajnoczi { 1259cdbcc18dSStefan Hajnoczi .name = "control-host", 1260cdbcc18dSStefan Hajnoczi .has_arg = required_argument, 1261cdbcc18dSStefan Hajnoczi .val = 'H', 1262cdbcc18dSStefan Hajnoczi }, 1263cdbcc18dSStefan Hajnoczi { 1264cdbcc18dSStefan Hajnoczi .name = "control-port", 1265cdbcc18dSStefan Hajnoczi .has_arg = required_argument, 1266cdbcc18dSStefan Hajnoczi .val = 'P', 1267cdbcc18dSStefan Hajnoczi }, 1268cdbcc18dSStefan Hajnoczi { 1269cdbcc18dSStefan Hajnoczi .name = "mode", 1270cdbcc18dSStefan Hajnoczi .has_arg = required_argument, 1271cdbcc18dSStefan Hajnoczi .val = 'm', 1272cdbcc18dSStefan Hajnoczi }, 1273cdbcc18dSStefan Hajnoczi { 1274cdbcc18dSStefan Hajnoczi .name = "peer-cid", 1275cdbcc18dSStefan Hajnoczi .has_arg = required_argument, 1276cdbcc18dSStefan Hajnoczi .val = 'p', 1277cdbcc18dSStefan Hajnoczi }, 1278cdbcc18dSStefan Hajnoczi { 12795a2b2425SStefano Garzarella .name = "list", 12805a2b2425SStefano Garzarella .has_arg = no_argument, 12815a2b2425SStefano Garzarella .val = 'l', 12825a2b2425SStefano Garzarella }, 12835a2b2425SStefano Garzarella { 12845a2b2425SStefano Garzarella .name = "skip", 12855a2b2425SStefano Garzarella .has_arg = required_argument, 12865a2b2425SStefano Garzarella .val = 's', 12875a2b2425SStefano Garzarella }, 12885a2b2425SStefano Garzarella { 1289cdbcc18dSStefan Hajnoczi .name = "help", 1290cdbcc18dSStefan Hajnoczi .has_arg = no_argument, 1291cdbcc18dSStefan Hajnoczi .val = '?', 1292cdbcc18dSStefan Hajnoczi }, 1293cdbcc18dSStefan Hajnoczi {}, 1294cdbcc18dSStefan Hajnoczi }; 1295cdbcc18dSStefan Hajnoczi 1296cdbcc18dSStefan Hajnoczi static void usage(void) 1297cdbcc18dSStefan Hajnoczi { 12985a2b2425SStefano Garzarella fprintf(stderr, "Usage: vsock_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid> [--list] [--skip=<test_id>]\n" 1299cdbcc18dSStefan Hajnoczi "\n" 1300cdbcc18dSStefan Hajnoczi " Server: vsock_test --control-port=1234 --mode=server --peer-cid=3\n" 1301cdbcc18dSStefan Hajnoczi " Client: vsock_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" 1302cdbcc18dSStefan Hajnoczi "\n" 1303cdbcc18dSStefan Hajnoczi "Run vsock.ko tests. Must be launched in both guest\n" 1304cdbcc18dSStefan Hajnoczi "and host. One side must use --mode=client and\n" 1305cdbcc18dSStefan Hajnoczi "the other side must use --mode=server.\n" 1306cdbcc18dSStefan Hajnoczi "\n" 1307cdbcc18dSStefan Hajnoczi "A TCP control socket connection is used to coordinate tests\n" 1308cdbcc18dSStefan Hajnoczi "between the client and the server. The server requires a\n" 1309cdbcc18dSStefan Hajnoczi "listen address and the client requires an address to\n" 1310cdbcc18dSStefan Hajnoczi "connect to.\n" 1311cdbcc18dSStefan Hajnoczi "\n" 13128d00b93fSStefano Garzarella "The CID of the other side must be given with --peer-cid=<cid>.\n" 13138d00b93fSStefano Garzarella "\n" 13148d00b93fSStefano Garzarella "Options:\n" 13158d00b93fSStefano Garzarella " --help This help message\n" 13168d00b93fSStefano Garzarella " --control-host <host> Server IP address to connect to\n" 13178d00b93fSStefano Garzarella " --control-port <port> Server port to listen on/connect to\n" 13188d00b93fSStefano Garzarella " --mode client|server Server or client mode\n" 13198d00b93fSStefano Garzarella " --peer-cid <cid> CID of the other side\n" 13208d00b93fSStefano Garzarella " --list List of tests that will be executed\n" 13218d00b93fSStefano Garzarella " --skip <test_id> Test ID to skip;\n" 13228d00b93fSStefano Garzarella " use multiple --skip options to skip more tests\n" 13238d00b93fSStefano Garzarella ); 1324cdbcc18dSStefan Hajnoczi exit(EXIT_FAILURE); 1325cdbcc18dSStefan Hajnoczi } 1326cdbcc18dSStefan Hajnoczi 1327cdbcc18dSStefan Hajnoczi int main(int argc, char **argv) 1328cdbcc18dSStefan Hajnoczi { 1329cdbcc18dSStefan Hajnoczi const char *control_host = NULL; 1330cdbcc18dSStefan Hajnoczi const char *control_port = NULL; 1331cdbcc18dSStefan Hajnoczi struct test_opts opts = { 1332cdbcc18dSStefan Hajnoczi .mode = TEST_MODE_UNSET, 1333cdbcc18dSStefan Hajnoczi .peer_cid = VMADDR_CID_ANY, 1334cdbcc18dSStefan Hajnoczi }; 1335cdbcc18dSStefan Hajnoczi 13365c338112SArseniy Krasnov srand(time(NULL)); 1337cdbcc18dSStefan Hajnoczi init_signals(); 1338cdbcc18dSStefan Hajnoczi 1339cdbcc18dSStefan Hajnoczi for (;;) { 1340cdbcc18dSStefan Hajnoczi int opt = getopt_long(argc, argv, optstring, longopts, NULL); 1341cdbcc18dSStefan Hajnoczi 1342cdbcc18dSStefan Hajnoczi if (opt == -1) 1343cdbcc18dSStefan Hajnoczi break; 1344cdbcc18dSStefan Hajnoczi 1345cdbcc18dSStefan Hajnoczi switch (opt) { 1346cdbcc18dSStefan Hajnoczi case 'H': 1347cdbcc18dSStefan Hajnoczi control_host = optarg; 1348cdbcc18dSStefan Hajnoczi break; 1349cdbcc18dSStefan Hajnoczi case 'm': 1350cdbcc18dSStefan Hajnoczi if (strcmp(optarg, "client") == 0) 1351cdbcc18dSStefan Hajnoczi opts.mode = TEST_MODE_CLIENT; 1352cdbcc18dSStefan Hajnoczi else if (strcmp(optarg, "server") == 0) 1353cdbcc18dSStefan Hajnoczi opts.mode = TEST_MODE_SERVER; 1354cdbcc18dSStefan Hajnoczi else { 1355cdbcc18dSStefan Hajnoczi fprintf(stderr, "--mode must be \"client\" or \"server\"\n"); 1356cdbcc18dSStefan Hajnoczi return EXIT_FAILURE; 1357cdbcc18dSStefan Hajnoczi } 1358cdbcc18dSStefan Hajnoczi break; 1359cdbcc18dSStefan Hajnoczi case 'p': 1360cdbcc18dSStefan Hajnoczi opts.peer_cid = parse_cid(optarg); 1361cdbcc18dSStefan Hajnoczi break; 1362cdbcc18dSStefan Hajnoczi case 'P': 1363cdbcc18dSStefan Hajnoczi control_port = optarg; 1364cdbcc18dSStefan Hajnoczi break; 13655a2b2425SStefano Garzarella case 'l': 13665a2b2425SStefano Garzarella list_tests(test_cases); 13675a2b2425SStefano Garzarella break; 13685a2b2425SStefano Garzarella case 's': 13695a2b2425SStefano Garzarella skip_test(test_cases, ARRAY_SIZE(test_cases) - 1, 13705a2b2425SStefano Garzarella optarg); 13715a2b2425SStefano Garzarella break; 1372cdbcc18dSStefan Hajnoczi case '?': 1373cdbcc18dSStefan Hajnoczi default: 1374cdbcc18dSStefan Hajnoczi usage(); 1375cdbcc18dSStefan Hajnoczi } 1376cdbcc18dSStefan Hajnoczi } 1377cdbcc18dSStefan Hajnoczi 1378cdbcc18dSStefan Hajnoczi if (!control_port) 1379cdbcc18dSStefan Hajnoczi usage(); 1380cdbcc18dSStefan Hajnoczi if (opts.mode == TEST_MODE_UNSET) 1381cdbcc18dSStefan Hajnoczi usage(); 1382cdbcc18dSStefan Hajnoczi if (opts.peer_cid == VMADDR_CID_ANY) 1383cdbcc18dSStefan Hajnoczi usage(); 1384cdbcc18dSStefan Hajnoczi 1385cdbcc18dSStefan Hajnoczi if (!control_host) { 1386cdbcc18dSStefan Hajnoczi if (opts.mode != TEST_MODE_SERVER) 1387cdbcc18dSStefan Hajnoczi usage(); 1388cdbcc18dSStefan Hajnoczi control_host = "0.0.0.0"; 1389cdbcc18dSStefan Hajnoczi } 1390cdbcc18dSStefan Hajnoczi 1391cdbcc18dSStefan Hajnoczi control_init(control_host, control_port, 1392cdbcc18dSStefan Hajnoczi opts.mode == TEST_MODE_SERVER); 1393cdbcc18dSStefan Hajnoczi 1394cdbcc18dSStefan Hajnoczi run_tests(test_cases, &opts); 1395cdbcc18dSStefan Hajnoczi 1396cdbcc18dSStefan Hajnoczi control_cleanup(); 1397cdbcc18dSStefan Hajnoczi return EXIT_SUCCESS; 1398cdbcc18dSStefan Hajnoczi } 1399