xref: /openbmc/qemu/tests/unit/test-iov.c (revision e2c41766)
1 #include "qemu/osdep.h"
2 #include "qemu/iov.h"
3 #include "qemu/sockets.h"
4 
5 /* create a randomly-sized iovec with random vectors */
iov_random(struct iovec ** iovp,unsigned * iov_cntp)6 static void iov_random(struct iovec **iovp, unsigned *iov_cntp)
7 {
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);
14      }
15      *iovp = iov;
16      *iov_cntp = niov;
17 }
18 
iov_free(struct iovec * iov,unsigned niov)19 static void iov_free(struct iovec *iov, unsigned niov)
20 {
21     unsigned i;
22     for (i = 0; i < niov; ++i) {
23         g_free(iov[i].iov_base);
24     }
25     g_free(iov);
26 }
27 
iov_equals(const struct iovec * a,const struct iovec * b,unsigned niov)28 static bool iov_equals(const struct iovec *a, const struct iovec *b,
29                        unsigned niov)
30 {
31     return memcmp(a, b, sizeof(a[0]) * niov) == 0;
32 }
33 
test_iov_bytes(struct iovec * iov,unsigned niov,size_t offset,size_t bytes)34 static void test_iov_bytes(struct iovec *iov, unsigned niov,
35                            size_t offset, size_t bytes)
36 {
37     unsigned i;
38     size_t j, o;
39     unsigned char *b;
40     o = 0;
41 
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);
54             }
55             ++o;
56         }
57     }
58 }
59 
test_to_from_buf_1(void)60 static void test_to_from_buf_1(void)
61 {
62      unsigned niov;
63      struct iovec *iov;
64      size_t sz;
65      unsigned char *ibuf, *obuf;
66      unsigned i, j, n;
67 
68      iov_random(&iov, &niov);
69 
70      sz = iov_size(iov, niov);
71 
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);
76 
77      /* fill in ibuf with 0123456... */
78      for (i = 0; i < sz; ++i) {
79          ibuf[i] = i & 255;
80      }
81 
82      for (i = 0; i <= sz; ++i) {
83 
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 */
87 
88          /* first set bytes [i..sz) to some "random" value */
89          n = iov_memset(iov, niov, 0, 0xff, sz);
90          g_assert(n == sz);
91 
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);
95 
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);
101 
102          /* now compare resulting buffers */
103          g_assert(memcmp(ibuf, obuf, sz) == 0);
104 
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));
110          }
111 
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]. */
115 
116              /* clear iovec */
117              n = iov_memset(iov, niov, 0, 0xff, sz);
118              g_assert(n == sz);
119 
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);
123 
124              /* clear part of obuf */
125              memset(obuf + i, 0, j - i);
126 
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);
130 
131              /* verify result */
132              g_assert(memcmp(ibuf, obuf, sz) == 0);
133 
134              /* now actually check if the iovec contains the right data */
135              test_iov_bytes(iov, niov, i, j - i);
136          }
137     }
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);
143 }
144 
test_to_from_buf(void)145 static void test_to_from_buf(void)
146 {
147     int x;
148     for (x = 0; x < 4; ++x) {
149         test_to_from_buf_1();
150     }
151 }
152 
test_io(void)153 static void test_io(void)
154 {
155 #ifndef _WIN32
156 /* socketpair(PF_UNIX) which does not exist on windows */
157 
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;
166 
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;
172     }
173     iov_from_buf(iov, niov, 0, buf, sz);
174 
175     siov = g_memdup2(iov, sizeof(*iov) * niov);
176 
177     if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
178        perror("socketpair");
179        exit(1);
180     }
181 
182     FD_ZERO(&fds);
183 
184     if (fork() == 0) {
185        /* writer */
186 
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));
192 
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);
206                         }
207                    }
208                    k += r;
209                    if (k < j) {
210                         select(sv[1] + 1, NULL, &fds, NULL, NULL);
211                    }
212                } while(k < j);
213            }
214        }
215        iov_free(iov, niov);
216        g_free(buf);
217        g_free(siov);
218        exit(0);
219 
220     } else {
221        /* reader & verifier */
222 
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);
229 
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;
243                        }
244                    } else if (errno == EAGAIN) {
245                        select(sv[0]+1, &fds, NULL, NULL, NULL);
246                        continue;
247                    } else {
248                        perror("recv");
249                        exit(1);
250                    }
251                } while(k < j);
252                test_iov_bytes(iov, niov, i, j - i);
253            }
254         }
255 
256        iov_free(iov, niov);
257        g_free(buf);
258        g_free(siov);
259      }
260 #endif
261 }
262 
test_discard_front(void)263 static void test_discard_front(void)
264 {
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;
272 
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);
282 
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);
292 
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);
302 
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);
316 
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);
326 
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);
340 }
341 
test_discard_front_undo(void)342 static void test_discard_front_undo(void)
343 {
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;
351 
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);
362 
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);
374 
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);
386 
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);
398 
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);
409 
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);
421 }
422 
test_discard_back(void)423 static void test_discard_back(void)
424 {
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;
431 
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);
439 
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);
448 
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);
457 
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);
468 
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);
478 
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);
490 }
491 
test_discard_back_undo(void)492 static void test_discard_back_undo(void)
493 {
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;
500 
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);
510 
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);
521 
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);
532 
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);
543 
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);
554 
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);
566 }
567 
main(int argc,char ** argv)568 int main(int argc, char **argv)
569 {
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();
579 }
580