xref: /openbmc/qemu/tests/unit/test-iov.c (revision f7a6df5f)
1 #include "qemu/osdep.h"
2 #include "qemu-common.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, t;
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_memdup(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     t = 0;
186     if (fork() == 0) {
187        /* writer */
188 
189        close(sv[0]);
190        FD_SET(sv[1], &fds);
191        fcntl(sv[1], F_SETFL, O_RDWR|O_NONBLOCK);
192        r = g_test_rand_int_range(sz / 2, sz);
193        setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r));
194 
195        for (i = 0; i <= sz; ++i) {
196            for (j = i; j <= sz; ++j) {
197                k = i;
198                do {
199                    s = g_test_rand_int_range(0, j - k + 1);
200                    r = iov_send(sv[1], iov, niov, k, s);
201                    g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
202                    if (r >= 0) {
203                        k += r;
204                        t += r;
205                        usleep(g_test_rand_int_range(0, 30));
206                    } else if (errno == EAGAIN) {
207                        select(sv[1]+1, NULL, &fds, NULL, NULL);
208                        continue;
209                    } else {
210                        perror("send");
211                        exit(1);
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        fcntl(sv[0], F_SETFL, O_RDWR|O_NONBLOCK);
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                        t += r;
242                    } else if (!r) {
243                        if (s) {
244                            break;
245                        }
246                    } else if (errno == EAGAIN) {
247                        select(sv[0]+1, &fds, NULL, NULL, NULL);
248                        continue;
249                    } else {
250                        perror("recv");
251                        exit(1);
252                    }
253                } while(k < j);
254                test_iov_bytes(iov, niov, i, j - i);
255            }
256         }
257 
258        iov_free(iov, niov);
259        g_free(buf);
260        g_free(siov);
261      }
262 #endif
263 }
264 
265 static void test_discard_front(void)
266 {
267     struct iovec *iov;
268     struct iovec *iov_tmp;
269     unsigned int iov_cnt;
270     unsigned int iov_cnt_tmp;
271     void *old_base;
272     size_t size;
273     size_t ret;
274 
275     /* Discard zero bytes */
276     iov_random(&iov, &iov_cnt);
277     iov_tmp = iov;
278     iov_cnt_tmp = iov_cnt;
279     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, 0);
280     g_assert(ret == 0);
281     g_assert(iov_tmp == iov);
282     g_assert(iov_cnt_tmp == iov_cnt);
283     iov_free(iov, iov_cnt);
284 
285     /* Discard more bytes than vector size */
286     iov_random(&iov, &iov_cnt);
287     iov_tmp = iov;
288     iov_cnt_tmp = iov_cnt;
289     size = iov_size(iov, iov_cnt);
290     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size + 1);
291     g_assert(ret == size);
292     g_assert(iov_cnt_tmp == 0);
293     iov_free(iov, iov_cnt);
294 
295     /* Discard entire vector */
296     iov_random(&iov, &iov_cnt);
297     iov_tmp = iov;
298     iov_cnt_tmp = iov_cnt;
299     size = iov_size(iov, iov_cnt);
300     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
301     g_assert(ret == size);
302     g_assert(iov_cnt_tmp == 0);
303     iov_free(iov, iov_cnt);
304 
305     /* Discard within first element */
306     iov_random(&iov, &iov_cnt);
307     iov_tmp = iov;
308     iov_cnt_tmp = iov_cnt;
309     old_base = iov->iov_base;
310     size = g_test_rand_int_range(1, iov->iov_len);
311     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
312     g_assert(ret == size);
313     g_assert(iov_tmp == iov);
314     g_assert(iov_cnt_tmp == iov_cnt);
315     g_assert(iov_tmp->iov_base == old_base + size);
316     iov_tmp->iov_base = old_base; /* undo before g_free() */
317     iov_free(iov, iov_cnt);
318 
319     /* Discard entire first element */
320     iov_random(&iov, &iov_cnt);
321     iov_tmp = iov;
322     iov_cnt_tmp = iov_cnt;
323     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, iov->iov_len);
324     g_assert(ret == iov->iov_len);
325     g_assert(iov_tmp == iov + 1);
326     g_assert(iov_cnt_tmp == iov_cnt - 1);
327     iov_free(iov, iov_cnt);
328 
329     /* Discard within second element */
330     iov_random(&iov, &iov_cnt);
331     iov_tmp = iov;
332     iov_cnt_tmp = iov_cnt;
333     old_base = iov[1].iov_base;
334     size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
335     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
336     g_assert(ret == size);
337     g_assert(iov_tmp == iov + 1);
338     g_assert(iov_cnt_tmp == iov_cnt - 1);
339     g_assert(iov_tmp->iov_base == old_base + (size - iov->iov_len));
340     iov_tmp->iov_base = old_base; /* undo before g_free() */
341     iov_free(iov, iov_cnt);
342 }
343 
344 static void test_discard_front_undo(void)
345 {
346     IOVDiscardUndo undo;
347     struct iovec *iov;
348     struct iovec *iov_tmp;
349     struct iovec *iov_orig;
350     unsigned int iov_cnt;
351     unsigned int iov_cnt_tmp;
352     size_t size;
353 
354     /* Discard zero bytes */
355     iov_random(&iov, &iov_cnt);
356     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
357     iov_tmp = iov;
358     iov_cnt_tmp = iov_cnt;
359     iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, 0, &undo);
360     iov_discard_undo(&undo);
361     assert(iov_equals(iov, iov_orig, iov_cnt));
362     g_free(iov_orig);
363     iov_free(iov, iov_cnt);
364 
365     /* Discard more bytes than vector size */
366     iov_random(&iov, &iov_cnt);
367     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
368     iov_tmp = iov;
369     iov_cnt_tmp = iov_cnt;
370     size = iov_size(iov, iov_cnt);
371     iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size + 1, &undo);
372     iov_discard_undo(&undo);
373     assert(iov_equals(iov, iov_orig, iov_cnt));
374     g_free(iov_orig);
375     iov_free(iov, iov_cnt);
376 
377     /* Discard entire vector */
378     iov_random(&iov, &iov_cnt);
379     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
380     iov_tmp = iov;
381     iov_cnt_tmp = iov_cnt;
382     size = iov_size(iov, iov_cnt);
383     iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
384     iov_discard_undo(&undo);
385     assert(iov_equals(iov, iov_orig, iov_cnt));
386     g_free(iov_orig);
387     iov_free(iov, iov_cnt);
388 
389     /* Discard within first element */
390     iov_random(&iov, &iov_cnt);
391     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
392     iov_tmp = iov;
393     iov_cnt_tmp = iov_cnt;
394     size = g_test_rand_int_range(1, iov->iov_len);
395     iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
396     iov_discard_undo(&undo);
397     assert(iov_equals(iov, iov_orig, iov_cnt));
398     g_free(iov_orig);
399     iov_free(iov, iov_cnt);
400 
401     /* Discard entire first element */
402     iov_random(&iov, &iov_cnt);
403     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
404     iov_tmp = iov;
405     iov_cnt_tmp = iov_cnt;
406     iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, iov->iov_len, &undo);
407     iov_discard_undo(&undo);
408     assert(iov_equals(iov, iov_orig, iov_cnt));
409     g_free(iov_orig);
410     iov_free(iov, iov_cnt);
411 
412     /* Discard within second element */
413     iov_random(&iov, &iov_cnt);
414     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
415     iov_tmp = iov;
416     iov_cnt_tmp = iov_cnt;
417     size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
418     iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
419     iov_discard_undo(&undo);
420     assert(iov_equals(iov, iov_orig, iov_cnt));
421     g_free(iov_orig);
422     iov_free(iov, iov_cnt);
423 }
424 
425 static void test_discard_back(void)
426 {
427     struct iovec *iov;
428     unsigned int iov_cnt;
429     unsigned int iov_cnt_tmp;
430     void *old_base;
431     size_t size;
432     size_t ret;
433 
434     /* Discard zero bytes */
435     iov_random(&iov, &iov_cnt);
436     iov_cnt_tmp = iov_cnt;
437     ret = iov_discard_back(iov, &iov_cnt_tmp, 0);
438     g_assert(ret == 0);
439     g_assert(iov_cnt_tmp == iov_cnt);
440     iov_free(iov, iov_cnt);
441 
442     /* Discard more bytes than vector size */
443     iov_random(&iov, &iov_cnt);
444     iov_cnt_tmp = iov_cnt;
445     size = iov_size(iov, iov_cnt);
446     ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1);
447     g_assert(ret == size);
448     g_assert(iov_cnt_tmp == 0);
449     iov_free(iov, iov_cnt);
450 
451     /* Discard entire vector */
452     iov_random(&iov, &iov_cnt);
453     iov_cnt_tmp = iov_cnt;
454     size = iov_size(iov, iov_cnt);
455     ret = iov_discard_back(iov, &iov_cnt_tmp, size);
456     g_assert(ret == size);
457     g_assert(iov_cnt_tmp == 0);
458     iov_free(iov, iov_cnt);
459 
460     /* Discard within last element */
461     iov_random(&iov, &iov_cnt);
462     iov_cnt_tmp = iov_cnt;
463     old_base = iov[iov_cnt - 1].iov_base;
464     size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
465     ret = iov_discard_back(iov, &iov_cnt_tmp, size);
466     g_assert(ret == size);
467     g_assert(iov_cnt_tmp == iov_cnt);
468     g_assert(iov[iov_cnt - 1].iov_base == old_base);
469     iov_free(iov, iov_cnt);
470 
471     /* Discard entire last element */
472     iov_random(&iov, &iov_cnt);
473     iov_cnt_tmp = iov_cnt;
474     old_base = iov[iov_cnt - 1].iov_base;
475     size = iov[iov_cnt - 1].iov_len;
476     ret = iov_discard_back(iov, &iov_cnt_tmp, size);
477     g_assert(ret == size);
478     g_assert(iov_cnt_tmp == iov_cnt - 1);
479     iov_free(iov, iov_cnt);
480 
481     /* Discard within second-to-last element */
482     iov_random(&iov, &iov_cnt);
483     iov_cnt_tmp = iov_cnt;
484     old_base = iov[iov_cnt - 2].iov_base;
485     size = iov[iov_cnt - 1].iov_len +
486            g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
487     ret = iov_discard_back(iov, &iov_cnt_tmp, size);
488     g_assert(ret == size);
489     g_assert(iov_cnt_tmp == iov_cnt - 1);
490     g_assert(iov[iov_cnt - 2].iov_base == old_base);
491     iov_free(iov, iov_cnt);
492 }
493 
494 static void test_discard_back_undo(void)
495 {
496     IOVDiscardUndo undo;
497     struct iovec *iov;
498     struct iovec *iov_orig;
499     unsigned int iov_cnt;
500     unsigned int iov_cnt_tmp;
501     size_t size;
502 
503     /* Discard zero bytes */
504     iov_random(&iov, &iov_cnt);
505     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
506     iov_cnt_tmp = iov_cnt;
507     iov_discard_back_undoable(iov, &iov_cnt_tmp, 0, &undo);
508     iov_discard_undo(&undo);
509     assert(iov_equals(iov, iov_orig, iov_cnt));
510     g_free(iov_orig);
511     iov_free(iov, iov_cnt);
512 
513     /* Discard more bytes than vector size */
514     iov_random(&iov, &iov_cnt);
515     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
516     iov_cnt_tmp = iov_cnt;
517     size = iov_size(iov, iov_cnt);
518     iov_discard_back_undoable(iov, &iov_cnt_tmp, size + 1, &undo);
519     iov_discard_undo(&undo);
520     assert(iov_equals(iov, iov_orig, iov_cnt));
521     g_free(iov_orig);
522     iov_free(iov, iov_cnt);
523 
524     /* Discard entire vector */
525     iov_random(&iov, &iov_cnt);
526     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
527     iov_cnt_tmp = iov_cnt;
528     size = iov_size(iov, iov_cnt);
529     iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
530     iov_discard_undo(&undo);
531     assert(iov_equals(iov, iov_orig, iov_cnt));
532     g_free(iov_orig);
533     iov_free(iov, iov_cnt);
534 
535     /* Discard within last element */
536     iov_random(&iov, &iov_cnt);
537     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
538     iov_cnt_tmp = iov_cnt;
539     size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
540     iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
541     iov_discard_undo(&undo);
542     assert(iov_equals(iov, iov_orig, iov_cnt));
543     g_free(iov_orig);
544     iov_free(iov, iov_cnt);
545 
546     /* Discard entire last element */
547     iov_random(&iov, &iov_cnt);
548     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
549     iov_cnt_tmp = iov_cnt;
550     size = iov[iov_cnt - 1].iov_len;
551     iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
552     iov_discard_undo(&undo);
553     assert(iov_equals(iov, iov_orig, iov_cnt));
554     g_free(iov_orig);
555     iov_free(iov, iov_cnt);
556 
557     /* Discard within second-to-last element */
558     iov_random(&iov, &iov_cnt);
559     iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
560     iov_cnt_tmp = iov_cnt;
561     size = iov[iov_cnt - 1].iov_len +
562            g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
563     iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
564     iov_discard_undo(&undo);
565     assert(iov_equals(iov, iov_orig, iov_cnt));
566     g_free(iov_orig);
567     iov_free(iov, iov_cnt);
568 }
569 
570 int main(int argc, char **argv)
571 {
572     g_test_init(&argc, &argv, NULL);
573     g_test_rand_int();
574     g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf);
575     g_test_add_func("/basic/iov/io", test_io);
576     g_test_add_func("/basic/iov/discard-front", test_discard_front);
577     g_test_add_func("/basic/iov/discard-back", test_discard_back);
578     g_test_add_func("/basic/iov/discard-front-undo", test_discard_front_undo);
579     g_test_add_func("/basic/iov/discard-back-undo", test_discard_back_undo);
580     return g_test_run();
581 }
582