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