1#include <glib.h>
2#include "qemu-common.h"
3#include "iov.h"
4#include "qemu_socket.h"
5
6
7static void iov_random(struct iovec **iovp, unsigned *iov_cntp)
8{
9 unsigned niov = g_test_rand_int_range(3,8);
10 struct iovec *iov = g_malloc(niov * sizeof(*iov));
11 unsigned i;
12 for (i = 0; i < niov; ++i) {
13 iov[i].iov_len = g_test_rand_int_range(5,20);
14 iov[i].iov_base = g_malloc(iov[i].iov_len);
15 }
16 *iovp = iov;
17 *iov_cntp = niov;
18}
19
20static void iov_free(struct iovec *iov, unsigned niov)
21{
22 unsigned i;
23 for (i = 0; i < niov; ++i) {
24 g_free(iov[i].iov_base);
25 }
26 g_free(iov);
27}
28
29static void test_iov_bytes(struct iovec *iov, unsigned niov,
30 size_t offset, size_t bytes)
31{
32 unsigned i;
33 size_t j, o;
34 unsigned char *b;
35 o = 0;
36
37
38 for (i = 0; i < niov; ++i) {
39 b = iov[i].iov_base;
40
41 for (j = 0; j < iov[i].iov_len; ++j) {
42
43
44
45 if (o >= offset && o < offset + bytes) {
46 g_assert(b[j] == (o & 255));
47 } else {
48 g_assert(b[j] == 0xff);
49 }
50 ++o;
51 }
52 }
53}
54
55static void test_to_from_buf_1(void)
56{
57 unsigned niov;
58 struct iovec *iov;
59 size_t sz;
60 unsigned char *ibuf, *obuf;
61 unsigned i, j, n;
62
63 iov_random(&iov, &niov);
64
65 sz = iov_size(iov, niov);
66
67 ibuf = g_malloc(sz + 8) + 4;
68 memcpy(ibuf-4, "aaaa", 4); memcpy(ibuf + sz, "bbbb", 4);
69 obuf = g_malloc(sz + 8) + 4;
70 memcpy(obuf-4, "xxxx", 4); memcpy(obuf + sz, "yyyy", 4);
71
72
73 for (i = 0; i < sz; ++i) {
74 ibuf[i] = i & 255;
75 }
76
77 for (i = 0; i <= sz; ++i) {
78
79
80
81
82
83
84 n = iov_memset(iov, niov, 0, 0xff, -1);
85 g_assert(n == sz);
86
87
88 n = iov_from_buf(iov, niov, i, ibuf + i, -1);
89 g_assert(n == sz - i);
90
91
92 memset(obuf + i, 0, sz - i);
93
94 n = iov_to_buf(iov, niov, i, obuf + i, -1);
95 g_assert(n == sz - i);
96
97
98 g_assert(memcmp(ibuf, obuf, sz) == 0);
99
100
101 n = iov_to_buf(iov, niov, i, obuf + i, 1);
102 g_assert(n == (i < sz));
103 if (n) {
104 g_assert(obuf[i] == (i & 255));
105 }
106
107 for (j = i; j <= sz; ++j) {
108
109
110
111
112 n = iov_memset(iov, niov, 0, 0xff, -1);
113 g_assert(n == sz);
114
115
116 n = iov_from_buf(iov, niov, i, ibuf + i, j - i);
117 g_assert(n == j - i);
118
119
120 memset(obuf + i, 0, j - i);
121
122
123 n = iov_to_buf(iov, niov, i, obuf + i, j - i);
124 g_assert(n == j - i);
125
126
127 g_assert(memcmp(ibuf, obuf, sz) == 0);
128
129
130 test_iov_bytes(iov, niov, i, j - i);
131 }
132 }
133 g_assert(!memcmp(ibuf-4, "aaaa", 4) && !memcmp(ibuf+sz, "bbbb", 4));
134 g_free(ibuf-4);
135 g_assert(!memcmp(obuf-4, "xxxx", 4) && !memcmp(obuf+sz, "yyyy", 4));
136 g_free(obuf-4);
137 iov_free(iov, niov);
138}
139
140static void test_to_from_buf(void)
141{
142 int x;
143 for (x = 0; x < 4; ++x) {
144 test_to_from_buf_1();
145 }
146}
147
148static void test_io(void)
149{
150#ifndef _WIN32
151
152
153 int sv[2];
154 int r;
155 unsigned i, j, k, s, t;
156 fd_set fds;
157 unsigned niov;
158 struct iovec *iov, *siov;
159 unsigned char *buf;
160 size_t sz;
161
162 iov_random(&iov, &niov);
163 sz = iov_size(iov, niov);
164 buf = g_malloc(sz);
165 for (i = 0; i < sz; ++i) {
166 buf[i] = i & 255;
167 }
168 iov_from_buf(iov, niov, 0, buf, sz);
169
170 siov = g_malloc(sizeof(*iov) * niov);
171 memcpy(siov, iov, sizeof(*iov) * niov);
172
173 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
174 perror("socketpair");
175 exit(1);
176 }
177
178 FD_ZERO(&fds);
179
180 t = 0;
181 if (fork() == 0) {
182
183
184 close(sv[0]);
185 FD_SET(sv[1], &fds);
186 fcntl(sv[1], F_SETFL, O_RDWR|O_NONBLOCK);
187 r = g_test_rand_int_range(sz / 2, sz);
188 setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r));
189
190 for (i = 0; i <= sz; ++i) {
191 for (j = i; j <= sz; ++j) {
192 k = i;
193 do {
194 s = g_test_rand_int_range(0, j - k + 1);
195 r = iov_send(sv[1], iov, niov, k, s);
196 g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
197 if (r >= 0) {
198 k += r;
199 t += r;
200 usleep(g_test_rand_int_range(0, 30));
201 } else if (errno == EAGAIN) {
202 select(sv[1]+1, NULL, &fds, NULL, NULL);
203 continue;
204 } else {
205 perror("send");
206 exit(1);
207 }
208 } while(k < j);
209 }
210 }
211 exit(0);
212
213 } else {
214
215
216 close(sv[1]);
217 FD_SET(sv[0], &fds);
218 fcntl(sv[0], F_SETFL, O_RDWR|O_NONBLOCK);
219 r = g_test_rand_int_range(sz / 2, sz);
220 setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r));
221 usleep(500000);
222
223 for (i = 0; i <= sz; ++i) {
224 for (j = i; j <= sz; ++j) {
225 k = i;
226 iov_memset(iov, niov, 0, 0xff, -1);
227 do {
228 s = g_test_rand_int_range(0, j - k + 1);
229 r = iov_recv(sv[0], iov, niov, k, s);
230 g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
231 if (r > 0) {
232 k += r;
233 t += r;
234 } else if (!r) {
235 if (s) {
236 break;
237 }
238 } else if (errno == EAGAIN) {
239 select(sv[0]+1, &fds, NULL, NULL, NULL);
240 continue;
241 } else {
242 perror("recv");
243 exit(1);
244 }
245 } while(k < j);
246 test_iov_bytes(iov, niov, i, j - i);
247 }
248 }
249 }
250#endif
251}
252
253int main(int argc, char **argv)
254{
255 g_test_init(&argc, &argv, NULL);
256 g_test_rand_int();
257 g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf);
258 g_test_add_func("/basic/iov/io", test_io);
259 return g_test_run();
260}
261