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