diff options
Diffstat (limited to 'tools/testing/vsock/util.c')
-rw-r--r-- | tools/testing/vsock/util.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index f40f45b36d2f..f838bcee3589 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -11,8 +11,10 @@ #include <stdio.h> #include <stdlib.h> #include <signal.h> +#include <unistd.h> #include "timeout.h" +#include "control.h" #include "util.h" /* Install signal handlers */ @@ -41,6 +43,112 @@ unsigned int parse_cid(const char *str) return n; } +/* Connect to <cid, port> and return the file descriptor. */ +int vsock_stream_connect(unsigned int cid, unsigned int port) +{ + union { + struct sockaddr sa; + struct sockaddr_vm svm; + } addr = { + .svm = { + .svm_family = AF_VSOCK, + .svm_port = port, + .svm_cid = cid, + }, + }; + int ret; + int fd; + + control_expectln("LISTENING"); + + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + + timeout_begin(TIMEOUT); + do { + ret = connect(fd, &addr.sa, sizeof(addr.svm)); + timeout_check("connect"); + } while (ret < 0 && errno == EINTR); + timeout_end(); + + if (ret < 0) { + int old_errno = errno; + + close(fd); + fd = -1; + errno = old_errno; + } + return fd; +} + +/* Listen on <cid, port> and return the first incoming connection. The remote + * address is stored to clientaddrp. clientaddrp may be NULL. + */ +int vsock_stream_accept(unsigned int cid, unsigned int port, + struct sockaddr_vm *clientaddrp) +{ + union { + struct sockaddr sa; + struct sockaddr_vm svm; + } addr = { + .svm = { + .svm_family = AF_VSOCK, + .svm_port = port, + .svm_cid = cid, + }, + }; + union { + struct sockaddr sa; + struct sockaddr_vm svm; + } clientaddr; + socklen_t clientaddr_len = sizeof(clientaddr.svm); + int fd; + int client_fd; + int old_errno; + + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + + if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { + perror("bind"); + exit(EXIT_FAILURE); + } + + if (listen(fd, 1) < 0) { + perror("listen"); + exit(EXIT_FAILURE); + } + + control_writeln("LISTENING"); + + timeout_begin(TIMEOUT); + do { + client_fd = accept(fd, &clientaddr.sa, &clientaddr_len); + timeout_check("accept"); + } while (client_fd < 0 && errno == EINTR); + timeout_end(); + + old_errno = errno; + close(fd); + errno = old_errno; + + if (client_fd < 0) + return client_fd; + + if (clientaddr_len != sizeof(clientaddr.svm)) { + fprintf(stderr, "unexpected addrlen from accept(2), %zu\n", + (size_t)clientaddr_len); + exit(EXIT_FAILURE); + } + if (clientaddr.sa.sa_family != AF_VSOCK) { + fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n", + clientaddr.sa.sa_family); + exit(EXIT_FAILURE); + } + + if (clientaddrp) + *clientaddrp = clientaddr.svm; + return client_fd; +} + /* Run test cases. The program terminates if a failure occurs. */ void run_tests(const struct test_case *test_cases, const struct test_opts *opts) |