Merge tag 'pull-request-2024-06-12' of https://gitlab.com/thuth/qemu into staging
[qemu/kevin.git] / tests / unit / test-iov.c
blob75bc3be00578e33a18ed0340e7d53e02dbcbd122
1 #include "qemu/osdep.h"
2 #include "qemu/iov.h"
3 #include "qemu/sockets.h"
5 /* create a randomly-sized iovec with random vectors */
6 static void iov_random(struct iovec **iovp, unsigned *iov_cntp)
8 unsigned niov = g_test_rand_int_range(3,8);
9 struct iovec *iov = g_malloc(niov * sizeof(*iov));
10 unsigned i;
11 for (i = 0; i < niov; ++i) {
12 iov[i].iov_len = g_test_rand_int_range(5,20);
13 iov[i].iov_base = g_malloc(iov[i].iov_len);
15 *iovp = iov;
16 *iov_cntp = niov;
19 static void iov_free(struct iovec *iov, unsigned niov)
21 unsigned i;
22 for (i = 0; i < niov; ++i) {
23 g_free(iov[i].iov_base);
25 g_free(iov);
28 static bool iov_equals(const struct iovec *a, const struct iovec *b,
29 unsigned niov)
31 return memcmp(a, b, sizeof(a[0]) * niov) == 0;
34 static void test_iov_bytes(struct iovec *iov, unsigned niov,
35 size_t offset, size_t bytes)
37 unsigned i;
38 size_t j, o;
39 unsigned char *b;
40 o = 0;
42 /* we walk over all elements, */
43 for (i = 0; i < niov; ++i) {
44 b = iov[i].iov_base;
45 /* over each char of each element, */
46 for (j = 0; j < iov[i].iov_len; ++j) {
47 /* counting each of them and
48 * verifying that the ones within [offset,offset+bytes)
49 * range are equal to the position number (o) */
50 if (o >= offset && o < offset + bytes) {
51 g_assert(b[j] == (o & 255));
52 } else {
53 g_assert(b[j] == 0xff);
55 ++o;
60 static void test_to_from_buf_1(void)
62 unsigned niov;
63 struct iovec *iov;
64 size_t sz;
65 unsigned char *ibuf, *obuf;
66 unsigned i, j, n;
68 iov_random(&iov, &niov);
70 sz = iov_size(iov, niov);
72 ibuf = g_malloc(sz + 8) + 4;
73 memcpy(ibuf-4, "aaaa", 4); memcpy(ibuf + sz, "bbbb", 4);
74 obuf = g_malloc(sz + 8) + 4;
75 memcpy(obuf-4, "xxxx", 4); memcpy(obuf + sz, "yyyy", 4);
77 /* fill in ibuf with 0123456... */
78 for (i = 0; i < sz; ++i) {
79 ibuf[i] = i & 255;
82 for (i = 0; i <= sz; ++i) {
84 /* Test from/to buf for offset(i) in [0..sz] up to the end of buffer.
85 * For last iteration with offset == sz, the procedure should
86 * skip whole vector and process exactly 0 bytes */
88 /* first set bytes [i..sz) to some "random" value */
89 n = iov_memset(iov, niov, 0, 0xff, sz);
90 g_assert(n == sz);
92 /* next copy bytes [i..sz) from ibuf to iovec */
93 n = iov_from_buf(iov, niov, i, ibuf + i, sz - i);
94 g_assert(n == sz - i);
96 /* clear part of obuf */
97 memset(obuf + i, 0, sz - i);
98 /* and set this part of obuf to values from iovec */
99 n = iov_to_buf(iov, niov, i, obuf + i, sz - i);
100 g_assert(n == sz - i);
102 /* now compare resulting buffers */
103 g_assert(memcmp(ibuf, obuf, sz) == 0);
105 /* test just one char */
106 n = iov_to_buf(iov, niov, i, obuf + i, 1);
107 g_assert(n == (i < sz));
108 if (n) {
109 g_assert(obuf[i] == (i & 255));
112 for (j = i; j <= sz; ++j) {
113 /* now test num of bytes cap up to byte no. j,
114 * with j in [i..sz]. */
116 /* clear iovec */
117 n = iov_memset(iov, niov, 0, 0xff, sz);
118 g_assert(n == sz);
120 /* copy bytes [i..j) from ibuf to iovec */
121 n = iov_from_buf(iov, niov, i, ibuf + i, j - i);
122 g_assert(n == j - i);
124 /* clear part of obuf */
125 memset(obuf + i, 0, j - i);
127 /* copy bytes [i..j) from iovec to obuf */
128 n = iov_to_buf(iov, niov, i, obuf + i, j - i);
129 g_assert(n == j - i);
131 /* verify result */
132 g_assert(memcmp(ibuf, obuf, sz) == 0);
134 /* now actually check if the iovec contains the right data */
135 test_iov_bytes(iov, niov, i, j - i);
138 g_assert(!memcmp(ibuf-4, "aaaa", 4) && !memcmp(ibuf+sz, "bbbb", 4));
139 g_free(ibuf-4);
140 g_assert(!memcmp(obuf-4, "xxxx", 4) && !memcmp(obuf+sz, "yyyy", 4));
141 g_free(obuf-4);
142 iov_free(iov, niov);
145 static void test_to_from_buf(void)
147 int x;
148 for (x = 0; x < 4; ++x) {
149 test_to_from_buf_1();
153 static void test_io(void)
155 #ifndef _WIN32
156 /* socketpair(PF_UNIX) which does not exist on windows */
158 int sv[2];
159 int r;
160 unsigned i, j, k, s;
161 fd_set fds;
162 unsigned niov;
163 struct iovec *iov, *siov;
164 unsigned char *buf;
165 size_t sz;
167 iov_random(&iov, &niov);
168 sz = iov_size(iov, niov);
169 buf = g_malloc(sz);
170 for (i = 0; i < sz; ++i) {
171 buf[i] = i & 255;
173 iov_from_buf(iov, niov, 0, buf, sz);
175 siov = g_memdup2(iov, sizeof(*iov) * niov);
177 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
178 perror("socketpair");
179 exit(1);
182 FD_ZERO(&fds);
184 if (fork() == 0) {
185 /* writer */
187 close(sv[0]);
188 FD_SET(sv[1], &fds);
189 g_unix_set_fd_nonblocking(sv[1], true, NULL);
190 r = g_test_rand_int_range(sz / 2, sz);
191 setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r));
193 for (i = 0; i <= sz; ++i) {
194 for (j = i; j <= sz; ++j) {
195 k = i;
196 do {
197 s = g_test_rand_int_range(0, j - k + 1);
198 r = iov_send(sv[1], iov, niov, k, s);
199 g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
200 if (r < 0) {
201 if (errno == EAGAIN) {
202 r = 0;
203 } else {
204 perror("send");
205 exit(1);
208 k += r;
209 if (k < j) {
210 select(sv[1] + 1, NULL, &fds, NULL, NULL);
212 } while(k < j);
215 iov_free(iov, niov);
216 g_free(buf);
217 g_free(siov);
218 exit(0);
220 } else {
221 /* reader & verifier */
223 close(sv[1]);
224 FD_SET(sv[0], &fds);
225 g_unix_set_fd_nonblocking(sv[0], true, NULL);
226 r = g_test_rand_int_range(sz / 2, sz);
227 setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r));
228 usleep(500000);
230 for (i = 0; i <= sz; ++i) {
231 for (j = i; j <= sz; ++j) {
232 k = i;
233 iov_memset(iov, niov, 0, 0xff, sz);
234 do {
235 s = g_test_rand_int_range(0, j - k + 1);
236 r = iov_recv(sv[0], iov, niov, k, s);
237 g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
238 if (r > 0) {
239 k += r;
240 } else if (!r) {
241 if (s) {
242 break;
244 } else if (errno == EAGAIN) {
245 select(sv[0]+1, &fds, NULL, NULL, NULL);
246 continue;
247 } else {
248 perror("recv");
249 exit(1);
251 } while(k < j);
252 test_iov_bytes(iov, niov, i, j - i);
256 iov_free(iov, niov);
257 g_free(buf);
258 g_free(siov);
260 #endif
263 static void test_discard_front(void)
265 struct iovec *iov;
266 struct iovec *iov_tmp;
267 unsigned int iov_cnt;
268 unsigned int iov_cnt_tmp;
269 void *old_base;
270 size_t size;
271 size_t ret;
273 /* Discard zero bytes */
274 iov_random(&iov, &iov_cnt);
275 iov_tmp = iov;
276 iov_cnt_tmp = iov_cnt;
277 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, 0);
278 g_assert(ret == 0);
279 g_assert(iov_tmp == iov);
280 g_assert(iov_cnt_tmp == iov_cnt);
281 iov_free(iov, iov_cnt);
283 /* Discard more bytes than vector size */
284 iov_random(&iov, &iov_cnt);
285 iov_tmp = iov;
286 iov_cnt_tmp = iov_cnt;
287 size = iov_size(iov, iov_cnt);
288 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size + 1);
289 g_assert(ret == size);
290 g_assert(iov_cnt_tmp == 0);
291 iov_free(iov, iov_cnt);
293 /* Discard entire vector */
294 iov_random(&iov, &iov_cnt);
295 iov_tmp = iov;
296 iov_cnt_tmp = iov_cnt;
297 size = iov_size(iov, iov_cnt);
298 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
299 g_assert(ret == size);
300 g_assert(iov_cnt_tmp == 0);
301 iov_free(iov, iov_cnt);
303 /* Discard within first element */
304 iov_random(&iov, &iov_cnt);
305 iov_tmp = iov;
306 iov_cnt_tmp = iov_cnt;
307 old_base = iov->iov_base;
308 size = g_test_rand_int_range(1, iov->iov_len);
309 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
310 g_assert(ret == size);
311 g_assert(iov_tmp == iov);
312 g_assert(iov_cnt_tmp == iov_cnt);
313 g_assert(iov_tmp->iov_base == old_base + size);
314 iov_tmp->iov_base = old_base; /* undo before g_free() */
315 iov_free(iov, iov_cnt);
317 /* Discard entire first element */
318 iov_random(&iov, &iov_cnt);
319 iov_tmp = iov;
320 iov_cnt_tmp = iov_cnt;
321 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, iov->iov_len);
322 g_assert(ret == iov->iov_len);
323 g_assert(iov_tmp == iov + 1);
324 g_assert(iov_cnt_tmp == iov_cnt - 1);
325 iov_free(iov, iov_cnt);
327 /* Discard within second element */
328 iov_random(&iov, &iov_cnt);
329 iov_tmp = iov;
330 iov_cnt_tmp = iov_cnt;
331 old_base = iov[1].iov_base;
332 size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
333 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
334 g_assert(ret == size);
335 g_assert(iov_tmp == iov + 1);
336 g_assert(iov_cnt_tmp == iov_cnt - 1);
337 g_assert(iov_tmp->iov_base == old_base + (size - iov->iov_len));
338 iov_tmp->iov_base = old_base; /* undo before g_free() */
339 iov_free(iov, iov_cnt);
342 static void test_discard_front_undo(void)
344 IOVDiscardUndo undo;
345 struct iovec *iov;
346 struct iovec *iov_tmp;
347 struct iovec *iov_orig;
348 unsigned int iov_cnt;
349 unsigned int iov_cnt_tmp;
350 size_t size;
352 /* Discard zero bytes */
353 iov_random(&iov, &iov_cnt);
354 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
355 iov_tmp = iov;
356 iov_cnt_tmp = iov_cnt;
357 iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, 0, &undo);
358 iov_discard_undo(&undo);
359 assert(iov_equals(iov, iov_orig, iov_cnt));
360 g_free(iov_orig);
361 iov_free(iov, iov_cnt);
363 /* Discard more bytes than vector size */
364 iov_random(&iov, &iov_cnt);
365 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
366 iov_tmp = iov;
367 iov_cnt_tmp = iov_cnt;
368 size = iov_size(iov, iov_cnt);
369 iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size + 1, &undo);
370 iov_discard_undo(&undo);
371 assert(iov_equals(iov, iov_orig, iov_cnt));
372 g_free(iov_orig);
373 iov_free(iov, iov_cnt);
375 /* Discard entire vector */
376 iov_random(&iov, &iov_cnt);
377 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
378 iov_tmp = iov;
379 iov_cnt_tmp = iov_cnt;
380 size = iov_size(iov, iov_cnt);
381 iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
382 iov_discard_undo(&undo);
383 assert(iov_equals(iov, iov_orig, iov_cnt));
384 g_free(iov_orig);
385 iov_free(iov, iov_cnt);
387 /* Discard within first element */
388 iov_random(&iov, &iov_cnt);
389 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
390 iov_tmp = iov;
391 iov_cnt_tmp = iov_cnt;
392 size = g_test_rand_int_range(1, iov->iov_len);
393 iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
394 iov_discard_undo(&undo);
395 assert(iov_equals(iov, iov_orig, iov_cnt));
396 g_free(iov_orig);
397 iov_free(iov, iov_cnt);
399 /* Discard entire first element */
400 iov_random(&iov, &iov_cnt);
401 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
402 iov_tmp = iov;
403 iov_cnt_tmp = iov_cnt;
404 iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, iov->iov_len, &undo);
405 iov_discard_undo(&undo);
406 assert(iov_equals(iov, iov_orig, iov_cnt));
407 g_free(iov_orig);
408 iov_free(iov, iov_cnt);
410 /* Discard within second element */
411 iov_random(&iov, &iov_cnt);
412 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
413 iov_tmp = iov;
414 iov_cnt_tmp = iov_cnt;
415 size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
416 iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
417 iov_discard_undo(&undo);
418 assert(iov_equals(iov, iov_orig, iov_cnt));
419 g_free(iov_orig);
420 iov_free(iov, iov_cnt);
423 static void test_discard_back(void)
425 struct iovec *iov;
426 unsigned int iov_cnt;
427 unsigned int iov_cnt_tmp;
428 void *old_base;
429 size_t size;
430 size_t ret;
432 /* Discard zero bytes */
433 iov_random(&iov, &iov_cnt);
434 iov_cnt_tmp = iov_cnt;
435 ret = iov_discard_back(iov, &iov_cnt_tmp, 0);
436 g_assert(ret == 0);
437 g_assert(iov_cnt_tmp == iov_cnt);
438 iov_free(iov, iov_cnt);
440 /* Discard more bytes than vector size */
441 iov_random(&iov, &iov_cnt);
442 iov_cnt_tmp = iov_cnt;
443 size = iov_size(iov, iov_cnt);
444 ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1);
445 g_assert(ret == size);
446 g_assert(iov_cnt_tmp == 0);
447 iov_free(iov, iov_cnt);
449 /* Discard entire vector */
450 iov_random(&iov, &iov_cnt);
451 iov_cnt_tmp = iov_cnt;
452 size = iov_size(iov, iov_cnt);
453 ret = iov_discard_back(iov, &iov_cnt_tmp, size);
454 g_assert(ret == size);
455 g_assert(iov_cnt_tmp == 0);
456 iov_free(iov, iov_cnt);
458 /* Discard within last element */
459 iov_random(&iov, &iov_cnt);
460 iov_cnt_tmp = iov_cnt;
461 old_base = iov[iov_cnt - 1].iov_base;
462 size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
463 ret = iov_discard_back(iov, &iov_cnt_tmp, size);
464 g_assert(ret == size);
465 g_assert(iov_cnt_tmp == iov_cnt);
466 g_assert(iov[iov_cnt - 1].iov_base == old_base);
467 iov_free(iov, iov_cnt);
469 /* Discard entire last element */
470 iov_random(&iov, &iov_cnt);
471 iov_cnt_tmp = iov_cnt;
472 old_base = iov[iov_cnt - 1].iov_base;
473 size = iov[iov_cnt - 1].iov_len;
474 ret = iov_discard_back(iov, &iov_cnt_tmp, size);
475 g_assert(ret == size);
476 g_assert(iov_cnt_tmp == iov_cnt - 1);
477 iov_free(iov, iov_cnt);
479 /* Discard within second-to-last element */
480 iov_random(&iov, &iov_cnt);
481 iov_cnt_tmp = iov_cnt;
482 old_base = iov[iov_cnt - 2].iov_base;
483 size = iov[iov_cnt - 1].iov_len +
484 g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
485 ret = iov_discard_back(iov, &iov_cnt_tmp, size);
486 g_assert(ret == size);
487 g_assert(iov_cnt_tmp == iov_cnt - 1);
488 g_assert(iov[iov_cnt - 2].iov_base == old_base);
489 iov_free(iov, iov_cnt);
492 static void test_discard_back_undo(void)
494 IOVDiscardUndo undo;
495 struct iovec *iov;
496 struct iovec *iov_orig;
497 unsigned int iov_cnt;
498 unsigned int iov_cnt_tmp;
499 size_t size;
501 /* Discard zero bytes */
502 iov_random(&iov, &iov_cnt);
503 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
504 iov_cnt_tmp = iov_cnt;
505 iov_discard_back_undoable(iov, &iov_cnt_tmp, 0, &undo);
506 iov_discard_undo(&undo);
507 assert(iov_equals(iov, iov_orig, iov_cnt));
508 g_free(iov_orig);
509 iov_free(iov, iov_cnt);
511 /* Discard more bytes than vector size */
512 iov_random(&iov, &iov_cnt);
513 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
514 iov_cnt_tmp = iov_cnt;
515 size = iov_size(iov, iov_cnt);
516 iov_discard_back_undoable(iov, &iov_cnt_tmp, size + 1, &undo);
517 iov_discard_undo(&undo);
518 assert(iov_equals(iov, iov_orig, iov_cnt));
519 g_free(iov_orig);
520 iov_free(iov, iov_cnt);
522 /* Discard entire vector */
523 iov_random(&iov, &iov_cnt);
524 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
525 iov_cnt_tmp = iov_cnt;
526 size = iov_size(iov, iov_cnt);
527 iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
528 iov_discard_undo(&undo);
529 assert(iov_equals(iov, iov_orig, iov_cnt));
530 g_free(iov_orig);
531 iov_free(iov, iov_cnt);
533 /* Discard within last element */
534 iov_random(&iov, &iov_cnt);
535 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
536 iov_cnt_tmp = iov_cnt;
537 size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
538 iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
539 iov_discard_undo(&undo);
540 assert(iov_equals(iov, iov_orig, iov_cnt));
541 g_free(iov_orig);
542 iov_free(iov, iov_cnt);
544 /* Discard entire last element */
545 iov_random(&iov, &iov_cnt);
546 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
547 iov_cnt_tmp = iov_cnt;
548 size = iov[iov_cnt - 1].iov_len;
549 iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
550 iov_discard_undo(&undo);
551 assert(iov_equals(iov, iov_orig, iov_cnt));
552 g_free(iov_orig);
553 iov_free(iov, iov_cnt);
555 /* Discard within second-to-last element */
556 iov_random(&iov, &iov_cnt);
557 iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
558 iov_cnt_tmp = iov_cnt;
559 size = iov[iov_cnt - 1].iov_len +
560 g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
561 iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
562 iov_discard_undo(&undo);
563 assert(iov_equals(iov, iov_orig, iov_cnt));
564 g_free(iov_orig);
565 iov_free(iov, iov_cnt);
568 int main(int argc, char **argv)
570 g_test_init(&argc, &argv, NULL);
571 g_test_rand_int();
572 g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf);
573 g_test_add_func("/basic/iov/io", test_io);
574 g_test_add_func("/basic/iov/discard-front", test_discard_front);
575 g_test_add_func("/basic/iov/discard-back", test_discard_back);
576 g_test_add_func("/basic/iov/discard-front-undo", test_discard_front_undo);
577 g_test_add_func("/basic/iov/discard-back-undo", test_discard_back_undo);
578 return g_test_run();