xref: /openbmc/qemu/tests/unit/test-iov.c (revision 623d7e3551a6fc5693c06ea938c60fe281b52e27)
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