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 */
iov_random(struct iovec ** iovp,unsigned * iov_cntp)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 
iov_free(struct iovec * iov,unsigned niov)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 
test_iov_bytes(struct iovec * iov,unsigned niov,size_t offset,size_t bytes)29 static void test_iov_bytes(struct iovec *iov, unsigned niov,
30                            size_t offset, size_t bytes)
31 {
32     unsigned i;
33     size_t j, o;
34     unsigned char *b;
35     o = 0;
36 
37     /* we walk over all elements, */
38     for (i = 0; i < niov; ++i) {
39         b = iov[i].iov_base;
40         /* over each char of each element, */
41         for (j = 0; j < iov[i].iov_len; ++j) {
42             /* counting each of them and
43              * verifying that the ones within [offset,offset+bytes)
44              * range are equal to the position number (o) */
45             if (o >= offset && o < offset + bytes) {
46                 g_assert(b[j] == (o & 255));
47             } else {
48                 g_assert(b[j] == 0xff);
49             }
50             ++o;
51         }
52     }
53 }
54 
test_to_from_buf_1(void)55 static void test_to_from_buf_1(void)
56 {
57      unsigned niov;
58      struct iovec *iov;
59      size_t sz;
60      unsigned char *ibuf, *obuf;
61      unsigned i, j, n;
62 
63      iov_random(&iov, &niov);
64 
65      sz = iov_size(iov, niov);
66 
67      ibuf = g_malloc(sz + 8) + 4;
68      memcpy(ibuf-4, "aaaa", 4); memcpy(ibuf + sz, "bbbb", 4);
69      obuf = g_malloc(sz + 8) + 4;
70      memcpy(obuf-4, "xxxx", 4); memcpy(obuf + sz, "yyyy", 4);
71 
72      /* fill in ibuf with 0123456... */
73      for (i = 0; i < sz; ++i) {
74          ibuf[i] = i & 255;
75      }
76 
77      for (i = 0; i <= sz; ++i) {
78 
79          /* Test from/to buf for offset(i) in [0..sz] up to the end of buffer.
80           * For last iteration with offset == sz, the procedure should
81           * skip whole vector and process exactly 0 bytes */
82 
83          /* first set bytes [i..sz) to some "random" value */
84          n = iov_memset(iov, niov, 0, 0xff, sz);
85          g_assert(n == sz);
86 
87          /* next copy bytes [i..sz) from ibuf to iovec */
88          n = iov_from_buf(iov, niov, i, ibuf + i, sz - i);
89          g_assert(n == sz - i);
90 
91          /* clear part of obuf */
92          memset(obuf + i, 0, sz - i);
93          /* and set this part of obuf to values from iovec */
94          n = iov_to_buf(iov, niov, i, obuf + i, sz - i);
95          g_assert(n == sz - i);
96 
97          /* now compare resulting buffers */
98          g_assert(memcmp(ibuf, obuf, sz) == 0);
99 
100          /* test just one char */
101          n = iov_to_buf(iov, niov, i, obuf + i, 1);
102          g_assert(n == (i < sz));
103          if (n) {
104              g_assert(obuf[i] == (i & 255));
105          }
106 
107          for (j = i; j <= sz; ++j) {
108              /* now test num of bytes cap up to byte no. j,
109               * with j in [i..sz]. */
110 
111              /* clear iovec */
112              n = iov_memset(iov, niov, 0, 0xff, sz);
113              g_assert(n == sz);
114 
115              /* copy bytes [i..j) from ibuf to iovec */
116              n = iov_from_buf(iov, niov, i, ibuf + i, j - i);
117              g_assert(n == j - i);
118 
119              /* clear part of obuf */
120              memset(obuf + i, 0, j - i);
121 
122              /* copy bytes [i..j) from iovec to obuf */
123              n = iov_to_buf(iov, niov, i, obuf + i, j - i);
124              g_assert(n == j - i);
125 
126              /* verify result */
127              g_assert(memcmp(ibuf, obuf, sz) == 0);
128 
129              /* now actually check if the iovec contains the right data */
130              test_iov_bytes(iov, niov, i, j - i);
131          }
132     }
133     g_assert(!memcmp(ibuf-4, "aaaa", 4) && !memcmp(ibuf+sz, "bbbb", 4));
134     g_free(ibuf-4);
135     g_assert(!memcmp(obuf-4, "xxxx", 4) && !memcmp(obuf+sz, "yyyy", 4));
136     g_free(obuf-4);
137     iov_free(iov, niov);
138 }
139 
test_to_from_buf(void)140 static void test_to_from_buf(void)
141 {
142     int x;
143     for (x = 0; x < 4; ++x) {
144         test_to_from_buf_1();
145     }
146 }
147 
test_io(void)148 static void test_io(void)
149 {
150 #ifndef _WIN32
151 /* socketpair(PF_UNIX) which does not exist on windows */
152 
153     int sv[2];
154     int r;
155     unsigned i, j, k, s, t;
156     fd_set fds;
157     unsigned niov;
158     struct iovec *iov, *siov;
159     unsigned char *buf;
160     size_t sz;
161 
162     iov_random(&iov, &niov);
163     sz = iov_size(iov, niov);
164     buf = g_malloc(sz);
165     for (i = 0; i < sz; ++i) {
166         buf[i] = i & 255;
167     }
168     iov_from_buf(iov, niov, 0, buf, sz);
169 
170     siov = g_memdup(iov, sizeof(*iov) * niov);
171 
172     if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
173        perror("socketpair");
174        exit(1);
175     }
176 
177     FD_ZERO(&fds);
178 
179     t = 0;
180     if (fork() == 0) {
181        /* writer */
182 
183        close(sv[0]);
184        FD_SET(sv[1], &fds);
185        fcntl(sv[1], F_SETFL, O_RDWR|O_NONBLOCK);
186        r = g_test_rand_int_range(sz / 2, sz);
187        setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r));
188 
189        for (i = 0; i <= sz; ++i) {
190            for (j = i; j <= sz; ++j) {
191                k = i;
192                do {
193                    s = g_test_rand_int_range(0, j - k + 1);
194                    r = iov_send(sv[1], iov, niov, k, s);
195                    g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
196                    if (r >= 0) {
197                        k += r;
198                        t += r;
199                        usleep(g_test_rand_int_range(0, 30));
200                    } else if (errno == EAGAIN) {
201                        select(sv[1]+1, NULL, &fds, NULL, NULL);
202                        continue;
203                    } else {
204                        perror("send");
205                        exit(1);
206                    }
207                } while(k < j);
208            }
209        }
210        iov_free(iov, niov);
211        g_free(buf);
212        g_free(siov);
213        exit(0);
214 
215     } else {
216        /* reader & verifier */
217 
218        close(sv[1]);
219        FD_SET(sv[0], &fds);
220        fcntl(sv[0], F_SETFL, O_RDWR|O_NONBLOCK);
221        r = g_test_rand_int_range(sz / 2, sz);
222        setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r));
223        usleep(500000);
224 
225        for (i = 0; i <= sz; ++i) {
226            for (j = i; j <= sz; ++j) {
227                k = i;
228                iov_memset(iov, niov, 0, 0xff, sz);
229                do {
230                    s = g_test_rand_int_range(0, j - k + 1);
231                    r = iov_recv(sv[0], iov, niov, k, s);
232                    g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
233                    if (r > 0) {
234                        k += r;
235                        t += r;
236                    } else if (!r) {
237                        if (s) {
238                            break;
239                        }
240                    } else if (errno == EAGAIN) {
241                        select(sv[0]+1, &fds, NULL, NULL, NULL);
242                        continue;
243                    } else {
244                        perror("recv");
245                        exit(1);
246                    }
247                } while(k < j);
248                test_iov_bytes(iov, niov, i, j - i);
249            }
250         }
251 
252        iov_free(iov, niov);
253        g_free(buf);
254        g_free(siov);
255      }
256 #endif
257 }
258 
test_discard_front(void)259 static void test_discard_front(void)
260 {
261     struct iovec *iov;
262     struct iovec *iov_tmp;
263     unsigned int iov_cnt;
264     unsigned int iov_cnt_tmp;
265     void *old_base;
266     size_t size;
267     size_t ret;
268 
269     /* Discard zero bytes */
270     iov_random(&iov, &iov_cnt);
271     iov_tmp = iov;
272     iov_cnt_tmp = iov_cnt;
273     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, 0);
274     g_assert(ret == 0);
275     g_assert(iov_tmp == iov);
276     g_assert(iov_cnt_tmp == iov_cnt);
277     iov_free(iov, iov_cnt);
278 
279     /* Discard more bytes than vector size */
280     iov_random(&iov, &iov_cnt);
281     iov_tmp = iov;
282     iov_cnt_tmp = iov_cnt;
283     size = iov_size(iov, iov_cnt);
284     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size + 1);
285     g_assert(ret == size);
286     g_assert(iov_cnt_tmp == 0);
287     iov_free(iov, iov_cnt);
288 
289     /* Discard entire vector */
290     iov_random(&iov, &iov_cnt);
291     iov_tmp = iov;
292     iov_cnt_tmp = iov_cnt;
293     size = iov_size(iov, iov_cnt);
294     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
295     g_assert(ret == size);
296     g_assert(iov_cnt_tmp == 0);
297     iov_free(iov, iov_cnt);
298 
299     /* Discard within first element */
300     iov_random(&iov, &iov_cnt);
301     iov_tmp = iov;
302     iov_cnt_tmp = iov_cnt;
303     old_base = iov->iov_base;
304     size = g_test_rand_int_range(1, iov->iov_len);
305     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
306     g_assert(ret == size);
307     g_assert(iov_tmp == iov);
308     g_assert(iov_cnt_tmp == iov_cnt);
309     g_assert(iov_tmp->iov_base == old_base + size);
310     iov_tmp->iov_base = old_base; /* undo before g_free() */
311     iov_free(iov, iov_cnt);
312 
313     /* Discard entire first element */
314     iov_random(&iov, &iov_cnt);
315     iov_tmp = iov;
316     iov_cnt_tmp = iov_cnt;
317     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, iov->iov_len);
318     g_assert(ret == iov->iov_len);
319     g_assert(iov_tmp == iov + 1);
320     g_assert(iov_cnt_tmp == iov_cnt - 1);
321     iov_free(iov, iov_cnt);
322 
323     /* Discard within second element */
324     iov_random(&iov, &iov_cnt);
325     iov_tmp = iov;
326     iov_cnt_tmp = iov_cnt;
327     old_base = iov[1].iov_base;
328     size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
329     ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
330     g_assert(ret == size);
331     g_assert(iov_tmp == iov + 1);
332     g_assert(iov_cnt_tmp == iov_cnt - 1);
333     g_assert(iov_tmp->iov_base == old_base + (size - iov->iov_len));
334     iov_tmp->iov_base = old_base; /* undo before g_free() */
335     iov_free(iov, iov_cnt);
336 }
337 
test_discard_back(void)338 static void test_discard_back(void)
339 {
340     struct iovec *iov;
341     unsigned int iov_cnt;
342     unsigned int iov_cnt_tmp;
343     void *old_base;
344     size_t size;
345     size_t ret;
346 
347     /* Discard zero bytes */
348     iov_random(&iov, &iov_cnt);
349     iov_cnt_tmp = iov_cnt;
350     ret = iov_discard_back(iov, &iov_cnt_tmp, 0);
351     g_assert(ret == 0);
352     g_assert(iov_cnt_tmp == iov_cnt);
353     iov_free(iov, iov_cnt);
354 
355     /* Discard more bytes than vector size */
356     iov_random(&iov, &iov_cnt);
357     iov_cnt_tmp = iov_cnt;
358     size = iov_size(iov, iov_cnt);
359     ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1);
360     g_assert(ret == size);
361     g_assert(iov_cnt_tmp == 0);
362     iov_free(iov, iov_cnt);
363 
364     /* Discard entire vector */
365     iov_random(&iov, &iov_cnt);
366     iov_cnt_tmp = iov_cnt;
367     size = iov_size(iov, iov_cnt);
368     ret = iov_discard_back(iov, &iov_cnt_tmp, size);
369     g_assert(ret == size);
370     g_assert(iov_cnt_tmp == 0);
371     iov_free(iov, iov_cnt);
372 
373     /* Discard within last element */
374     iov_random(&iov, &iov_cnt);
375     iov_cnt_tmp = iov_cnt;
376     old_base = iov[iov_cnt - 1].iov_base;
377     size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
378     ret = iov_discard_back(iov, &iov_cnt_tmp, size);
379     g_assert(ret == size);
380     g_assert(iov_cnt_tmp == iov_cnt);
381     g_assert(iov[iov_cnt - 1].iov_base == old_base);
382     iov_free(iov, iov_cnt);
383 
384     /* Discard entire last element */
385     iov_random(&iov, &iov_cnt);
386     iov_cnt_tmp = iov_cnt;
387     old_base = iov[iov_cnt - 1].iov_base;
388     size = iov[iov_cnt - 1].iov_len;
389     ret = iov_discard_back(iov, &iov_cnt_tmp, size);
390     g_assert(ret == size);
391     g_assert(iov_cnt_tmp == iov_cnt - 1);
392     iov_free(iov, iov_cnt);
393 
394     /* Discard within second-to-last element */
395     iov_random(&iov, &iov_cnt);
396     iov_cnt_tmp = iov_cnt;
397     old_base = iov[iov_cnt - 2].iov_base;
398     size = iov[iov_cnt - 1].iov_len +
399            g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
400     ret = iov_discard_back(iov, &iov_cnt_tmp, size);
401     g_assert(ret == size);
402     g_assert(iov_cnt_tmp == iov_cnt - 1);
403     g_assert(iov[iov_cnt - 2].iov_base == old_base);
404     iov_free(iov, iov_cnt);
405 }
406 
main(int argc,char ** argv)407 int main(int argc, char **argv)
408 {
409     g_test_init(&argc, &argv, NULL);
410     g_test_rand_int();
411     g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf);
412     g_test_add_func("/basic/iov/io", test_io);
413     g_test_add_func("/basic/iov/discard-front", test_discard_front);
414     g_test_add_func("/basic/iov/discard-back", test_discard_back);
415     return g_test_run();
416 }
417