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