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