1da668aa1SThomas Huth #include "qemu/osdep.h"
2da668aa1SThomas Huth #include "qemu/iov.h"
3da668aa1SThomas Huth #include "qemu/sockets.h"
4da668aa1SThomas Huth
5da668aa1SThomas Huth /* create a randomly-sized iovec with random vectors */
iov_random(struct iovec ** iovp,unsigned * iov_cntp)6da668aa1SThomas Huth static void iov_random(struct iovec **iovp, unsigned *iov_cntp)
7da668aa1SThomas Huth {
8da668aa1SThomas Huth unsigned niov = g_test_rand_int_range(3,8);
9da668aa1SThomas Huth struct iovec *iov = g_malloc(niov * sizeof(*iov));
10da668aa1SThomas Huth unsigned i;
11da668aa1SThomas Huth for (i = 0; i < niov; ++i) {
12da668aa1SThomas Huth iov[i].iov_len = g_test_rand_int_range(5,20);
13da668aa1SThomas Huth iov[i].iov_base = g_malloc(iov[i].iov_len);
14da668aa1SThomas Huth }
15da668aa1SThomas Huth *iovp = iov;
16da668aa1SThomas Huth *iov_cntp = niov;
17da668aa1SThomas Huth }
18da668aa1SThomas Huth
iov_free(struct iovec * iov,unsigned niov)19da668aa1SThomas Huth static void iov_free(struct iovec *iov, unsigned niov)
20da668aa1SThomas Huth {
21da668aa1SThomas Huth unsigned i;
22da668aa1SThomas Huth for (i = 0; i < niov; ++i) {
23da668aa1SThomas Huth g_free(iov[i].iov_base);
24da668aa1SThomas Huth }
25da668aa1SThomas Huth g_free(iov);
26da668aa1SThomas Huth }
27da668aa1SThomas Huth
iov_equals(const struct iovec * a,const struct iovec * b,unsigned niov)28da668aa1SThomas Huth static bool iov_equals(const struct iovec *a, const struct iovec *b,
29da668aa1SThomas Huth unsigned niov)
30da668aa1SThomas Huth {
31da668aa1SThomas Huth return memcmp(a, b, sizeof(a[0]) * niov) == 0;
32da668aa1SThomas Huth }
33da668aa1SThomas Huth
test_iov_bytes(struct iovec * iov,unsigned niov,size_t offset,size_t bytes)34da668aa1SThomas Huth static void test_iov_bytes(struct iovec *iov, unsigned niov,
35da668aa1SThomas Huth size_t offset, size_t bytes)
36da668aa1SThomas Huth {
37da668aa1SThomas Huth unsigned i;
38da668aa1SThomas Huth size_t j, o;
39da668aa1SThomas Huth unsigned char *b;
40da668aa1SThomas Huth o = 0;
41da668aa1SThomas Huth
42da668aa1SThomas Huth /* we walk over all elements, */
43da668aa1SThomas Huth for (i = 0; i < niov; ++i) {
44da668aa1SThomas Huth b = iov[i].iov_base;
45da668aa1SThomas Huth /* over each char of each element, */
46da668aa1SThomas Huth for (j = 0; j < iov[i].iov_len; ++j) {
47da668aa1SThomas Huth /* counting each of them and
48da668aa1SThomas Huth * verifying that the ones within [offset,offset+bytes)
49da668aa1SThomas Huth * range are equal to the position number (o) */
50da668aa1SThomas Huth if (o >= offset && o < offset + bytes) {
51da668aa1SThomas Huth g_assert(b[j] == (o & 255));
52da668aa1SThomas Huth } else {
53da668aa1SThomas Huth g_assert(b[j] == 0xff);
54da668aa1SThomas Huth }
55da668aa1SThomas Huth ++o;
56da668aa1SThomas Huth }
57da668aa1SThomas Huth }
58da668aa1SThomas Huth }
59da668aa1SThomas Huth
test_to_from_buf_1(void)60da668aa1SThomas Huth static void test_to_from_buf_1(void)
61da668aa1SThomas Huth {
62da668aa1SThomas Huth unsigned niov;
63da668aa1SThomas Huth struct iovec *iov;
64da668aa1SThomas Huth size_t sz;
65da668aa1SThomas Huth unsigned char *ibuf, *obuf;
66da668aa1SThomas Huth unsigned i, j, n;
67da668aa1SThomas Huth
68da668aa1SThomas Huth iov_random(&iov, &niov);
69da668aa1SThomas Huth
70da668aa1SThomas Huth sz = iov_size(iov, niov);
71da668aa1SThomas Huth
72da668aa1SThomas Huth ibuf = g_malloc(sz + 8) + 4;
73da668aa1SThomas Huth memcpy(ibuf-4, "aaaa", 4); memcpy(ibuf + sz, "bbbb", 4);
74da668aa1SThomas Huth obuf = g_malloc(sz + 8) + 4;
75da668aa1SThomas Huth memcpy(obuf-4, "xxxx", 4); memcpy(obuf + sz, "yyyy", 4);
76da668aa1SThomas Huth
77da668aa1SThomas Huth /* fill in ibuf with 0123456... */
78da668aa1SThomas Huth for (i = 0; i < sz; ++i) {
79da668aa1SThomas Huth ibuf[i] = i & 255;
80da668aa1SThomas Huth }
81da668aa1SThomas Huth
82da668aa1SThomas Huth for (i = 0; i <= sz; ++i) {
83da668aa1SThomas Huth
84da668aa1SThomas Huth /* Test from/to buf for offset(i) in [0..sz] up to the end of buffer.
85da668aa1SThomas Huth * For last iteration with offset == sz, the procedure should
86da668aa1SThomas Huth * skip whole vector and process exactly 0 bytes */
87da668aa1SThomas Huth
88da668aa1SThomas Huth /* first set bytes [i..sz) to some "random" value */
89da668aa1SThomas Huth n = iov_memset(iov, niov, 0, 0xff, sz);
90da668aa1SThomas Huth g_assert(n == sz);
91da668aa1SThomas Huth
92da668aa1SThomas Huth /* next copy bytes [i..sz) from ibuf to iovec */
93da668aa1SThomas Huth n = iov_from_buf(iov, niov, i, ibuf + i, sz - i);
94da668aa1SThomas Huth g_assert(n == sz - i);
95da668aa1SThomas Huth
96da668aa1SThomas Huth /* clear part of obuf */
97da668aa1SThomas Huth memset(obuf + i, 0, sz - i);
98da668aa1SThomas Huth /* and set this part of obuf to values from iovec */
99da668aa1SThomas Huth n = iov_to_buf(iov, niov, i, obuf + i, sz - i);
100da668aa1SThomas Huth g_assert(n == sz - i);
101da668aa1SThomas Huth
102da668aa1SThomas Huth /* now compare resulting buffers */
103da668aa1SThomas Huth g_assert(memcmp(ibuf, obuf, sz) == 0);
104da668aa1SThomas Huth
105da668aa1SThomas Huth /* test just one char */
106da668aa1SThomas Huth n = iov_to_buf(iov, niov, i, obuf + i, 1);
107da668aa1SThomas Huth g_assert(n == (i < sz));
108da668aa1SThomas Huth if (n) {
109da668aa1SThomas Huth g_assert(obuf[i] == (i & 255));
110da668aa1SThomas Huth }
111da668aa1SThomas Huth
112da668aa1SThomas Huth for (j = i; j <= sz; ++j) {
113da668aa1SThomas Huth /* now test num of bytes cap up to byte no. j,
114da668aa1SThomas Huth * with j in [i..sz]. */
115da668aa1SThomas Huth
116da668aa1SThomas Huth /* clear iovec */
117da668aa1SThomas Huth n = iov_memset(iov, niov, 0, 0xff, sz);
118da668aa1SThomas Huth g_assert(n == sz);
119da668aa1SThomas Huth
120da668aa1SThomas Huth /* copy bytes [i..j) from ibuf to iovec */
121da668aa1SThomas Huth n = iov_from_buf(iov, niov, i, ibuf + i, j - i);
122da668aa1SThomas Huth g_assert(n == j - i);
123da668aa1SThomas Huth
124da668aa1SThomas Huth /* clear part of obuf */
125da668aa1SThomas Huth memset(obuf + i, 0, j - i);
126da668aa1SThomas Huth
127da668aa1SThomas Huth /* copy bytes [i..j) from iovec to obuf */
128da668aa1SThomas Huth n = iov_to_buf(iov, niov, i, obuf + i, j - i);
129da668aa1SThomas Huth g_assert(n == j - i);
130da668aa1SThomas Huth
131da668aa1SThomas Huth /* verify result */
132da668aa1SThomas Huth g_assert(memcmp(ibuf, obuf, sz) == 0);
133da668aa1SThomas Huth
134da668aa1SThomas Huth /* now actually check if the iovec contains the right data */
135da668aa1SThomas Huth test_iov_bytes(iov, niov, i, j - i);
136da668aa1SThomas Huth }
137da668aa1SThomas Huth }
138da668aa1SThomas Huth g_assert(!memcmp(ibuf-4, "aaaa", 4) && !memcmp(ibuf+sz, "bbbb", 4));
139da668aa1SThomas Huth g_free(ibuf-4);
140da668aa1SThomas Huth g_assert(!memcmp(obuf-4, "xxxx", 4) && !memcmp(obuf+sz, "yyyy", 4));
141da668aa1SThomas Huth g_free(obuf-4);
142da668aa1SThomas Huth iov_free(iov, niov);
143da668aa1SThomas Huth }
144da668aa1SThomas Huth
test_to_from_buf(void)145da668aa1SThomas Huth static void test_to_from_buf(void)
146da668aa1SThomas Huth {
147da668aa1SThomas Huth int x;
148da668aa1SThomas Huth for (x = 0; x < 4; ++x) {
149da668aa1SThomas Huth test_to_from_buf_1();
150da668aa1SThomas Huth }
151da668aa1SThomas Huth }
152da668aa1SThomas Huth
test_io(void)153da668aa1SThomas Huth static void test_io(void)
154da668aa1SThomas Huth {
155da668aa1SThomas Huth #ifndef _WIN32
156da668aa1SThomas Huth /* socketpair(PF_UNIX) which does not exist on windows */
157da668aa1SThomas Huth
158da668aa1SThomas Huth int sv[2];
159da668aa1SThomas Huth int r;
1602bf07e78SRichard Henderson unsigned i, j, k, s;
161da668aa1SThomas Huth fd_set fds;
162da668aa1SThomas Huth unsigned niov;
163da668aa1SThomas Huth struct iovec *iov, *siov;
164da668aa1SThomas Huth unsigned char *buf;
165da668aa1SThomas Huth size_t sz;
166da668aa1SThomas Huth
167da668aa1SThomas Huth iov_random(&iov, &niov);
168da668aa1SThomas Huth sz = iov_size(iov, niov);
169da668aa1SThomas Huth buf = g_malloc(sz);
170da668aa1SThomas Huth for (i = 0; i < sz; ++i) {
171da668aa1SThomas Huth buf[i] = i & 255;
172da668aa1SThomas Huth }
173da668aa1SThomas Huth iov_from_buf(iov, niov, 0, buf, sz);
174da668aa1SThomas Huth
175c4f8ce24SPhilippe Mathieu-Daudé siov = g_memdup2(iov, sizeof(*iov) * niov);
176da668aa1SThomas Huth
177da668aa1SThomas Huth if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
178da668aa1SThomas Huth perror("socketpair");
179da668aa1SThomas Huth exit(1);
180da668aa1SThomas Huth }
181da668aa1SThomas Huth
182da668aa1SThomas Huth FD_ZERO(&fds);
183da668aa1SThomas Huth
184da668aa1SThomas Huth if (fork() == 0) {
185da668aa1SThomas Huth /* writer */
186da668aa1SThomas Huth
187da668aa1SThomas Huth close(sv[0]);
188da668aa1SThomas Huth FD_SET(sv[1], &fds);
18922e135fcSMarc-André Lureau g_unix_set_fd_nonblocking(sv[1], true, NULL);
190da668aa1SThomas Huth r = g_test_rand_int_range(sz / 2, sz);
191da668aa1SThomas Huth setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r));
192da668aa1SThomas Huth
193da668aa1SThomas Huth for (i = 0; i <= sz; ++i) {
194da668aa1SThomas Huth for (j = i; j <= sz; ++j) {
195da668aa1SThomas Huth k = i;
196da668aa1SThomas Huth do {
197da668aa1SThomas Huth s = g_test_rand_int_range(0, j - k + 1);
198da668aa1SThomas Huth r = iov_send(sv[1], iov, niov, k, s);
199da668aa1SThomas Huth g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
200*e2c41766SThomas Huth if (r < 0) {
201*e2c41766SThomas Huth if (errno == EAGAIN) {
202*e2c41766SThomas Huth r = 0;
203da668aa1SThomas Huth } else {
204da668aa1SThomas Huth perror("send");
205da668aa1SThomas Huth exit(1);
206da668aa1SThomas Huth }
207*e2c41766SThomas Huth }
208*e2c41766SThomas Huth k += r;
209*e2c41766SThomas Huth if (k < j) {
210*e2c41766SThomas Huth select(sv[1] + 1, NULL, &fds, NULL, NULL);
211*e2c41766SThomas Huth }
212da668aa1SThomas Huth } while(k < j);
213da668aa1SThomas Huth }
214da668aa1SThomas Huth }
215da668aa1SThomas Huth iov_free(iov, niov);
216da668aa1SThomas Huth g_free(buf);
217da668aa1SThomas Huth g_free(siov);
218da668aa1SThomas Huth exit(0);
219da668aa1SThomas Huth
220da668aa1SThomas Huth } else {
221da668aa1SThomas Huth /* reader & verifier */
222da668aa1SThomas Huth
223da668aa1SThomas Huth close(sv[1]);
224da668aa1SThomas Huth FD_SET(sv[0], &fds);
22522e135fcSMarc-André Lureau g_unix_set_fd_nonblocking(sv[0], true, NULL);
226da668aa1SThomas Huth r = g_test_rand_int_range(sz / 2, sz);
227da668aa1SThomas Huth setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r));
228da668aa1SThomas Huth usleep(500000);
229da668aa1SThomas Huth
230da668aa1SThomas Huth for (i = 0; i <= sz; ++i) {
231da668aa1SThomas Huth for (j = i; j <= sz; ++j) {
232da668aa1SThomas Huth k = i;
233da668aa1SThomas Huth iov_memset(iov, niov, 0, 0xff, sz);
234da668aa1SThomas Huth do {
235da668aa1SThomas Huth s = g_test_rand_int_range(0, j - k + 1);
236da668aa1SThomas Huth r = iov_recv(sv[0], iov, niov, k, s);
237da668aa1SThomas Huth g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
238da668aa1SThomas Huth if (r > 0) {
239da668aa1SThomas Huth k += r;
240da668aa1SThomas Huth } else if (!r) {
241da668aa1SThomas Huth if (s) {
242da668aa1SThomas Huth break;
243da668aa1SThomas Huth }
244da668aa1SThomas Huth } else if (errno == EAGAIN) {
245da668aa1SThomas Huth select(sv[0]+1, &fds, NULL, NULL, NULL);
246da668aa1SThomas Huth continue;
247da668aa1SThomas Huth } else {
248da668aa1SThomas Huth perror("recv");
249da668aa1SThomas Huth exit(1);
250da668aa1SThomas Huth }
251da668aa1SThomas Huth } while(k < j);
252da668aa1SThomas Huth test_iov_bytes(iov, niov, i, j - i);
253da668aa1SThomas Huth }
254da668aa1SThomas Huth }
255da668aa1SThomas Huth
256da668aa1SThomas Huth iov_free(iov, niov);
257da668aa1SThomas Huth g_free(buf);
258da668aa1SThomas Huth g_free(siov);
259da668aa1SThomas Huth }
260da668aa1SThomas Huth #endif
261da668aa1SThomas Huth }
262da668aa1SThomas Huth
test_discard_front(void)263da668aa1SThomas Huth static void test_discard_front(void)
264da668aa1SThomas Huth {
265da668aa1SThomas Huth struct iovec *iov;
266da668aa1SThomas Huth struct iovec *iov_tmp;
267da668aa1SThomas Huth unsigned int iov_cnt;
268da668aa1SThomas Huth unsigned int iov_cnt_tmp;
269da668aa1SThomas Huth void *old_base;
270da668aa1SThomas Huth size_t size;
271da668aa1SThomas Huth size_t ret;
272da668aa1SThomas Huth
273da668aa1SThomas Huth /* Discard zero bytes */
274da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
275da668aa1SThomas Huth iov_tmp = iov;
276da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
277da668aa1SThomas Huth ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, 0);
278da668aa1SThomas Huth g_assert(ret == 0);
279da668aa1SThomas Huth g_assert(iov_tmp == iov);
280da668aa1SThomas Huth g_assert(iov_cnt_tmp == iov_cnt);
281da668aa1SThomas Huth iov_free(iov, iov_cnt);
282da668aa1SThomas Huth
283da668aa1SThomas Huth /* Discard more bytes than vector size */
284da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
285da668aa1SThomas Huth iov_tmp = iov;
286da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
287da668aa1SThomas Huth size = iov_size(iov, iov_cnt);
288da668aa1SThomas Huth ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size + 1);
289da668aa1SThomas Huth g_assert(ret == size);
290da668aa1SThomas Huth g_assert(iov_cnt_tmp == 0);
291da668aa1SThomas Huth iov_free(iov, iov_cnt);
292da668aa1SThomas Huth
293da668aa1SThomas Huth /* Discard entire vector */
294da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
295da668aa1SThomas Huth iov_tmp = iov;
296da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
297da668aa1SThomas Huth size = iov_size(iov, iov_cnt);
298da668aa1SThomas Huth ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
299da668aa1SThomas Huth g_assert(ret == size);
300da668aa1SThomas Huth g_assert(iov_cnt_tmp == 0);
301da668aa1SThomas Huth iov_free(iov, iov_cnt);
302da668aa1SThomas Huth
303da668aa1SThomas Huth /* Discard within first element */
304da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
305da668aa1SThomas Huth iov_tmp = iov;
306da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
307da668aa1SThomas Huth old_base = iov->iov_base;
308da668aa1SThomas Huth size = g_test_rand_int_range(1, iov->iov_len);
309da668aa1SThomas Huth ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
310da668aa1SThomas Huth g_assert(ret == size);
311da668aa1SThomas Huth g_assert(iov_tmp == iov);
312da668aa1SThomas Huth g_assert(iov_cnt_tmp == iov_cnt);
313da668aa1SThomas Huth g_assert(iov_tmp->iov_base == old_base + size);
314da668aa1SThomas Huth iov_tmp->iov_base = old_base; /* undo before g_free() */
315da668aa1SThomas Huth iov_free(iov, iov_cnt);
316da668aa1SThomas Huth
317da668aa1SThomas Huth /* Discard entire first element */
318da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
319da668aa1SThomas Huth iov_tmp = iov;
320da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
321da668aa1SThomas Huth ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, iov->iov_len);
322da668aa1SThomas Huth g_assert(ret == iov->iov_len);
323da668aa1SThomas Huth g_assert(iov_tmp == iov + 1);
324da668aa1SThomas Huth g_assert(iov_cnt_tmp == iov_cnt - 1);
325da668aa1SThomas Huth iov_free(iov, iov_cnt);
326da668aa1SThomas Huth
327da668aa1SThomas Huth /* Discard within second element */
328da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
329da668aa1SThomas Huth iov_tmp = iov;
330da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
331da668aa1SThomas Huth old_base = iov[1].iov_base;
332da668aa1SThomas Huth size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
333da668aa1SThomas Huth ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
334da668aa1SThomas Huth g_assert(ret == size);
335da668aa1SThomas Huth g_assert(iov_tmp == iov + 1);
336da668aa1SThomas Huth g_assert(iov_cnt_tmp == iov_cnt - 1);
337da668aa1SThomas Huth g_assert(iov_tmp->iov_base == old_base + (size - iov->iov_len));
338da668aa1SThomas Huth iov_tmp->iov_base = old_base; /* undo before g_free() */
339da668aa1SThomas Huth iov_free(iov, iov_cnt);
340da668aa1SThomas Huth }
341da668aa1SThomas Huth
test_discard_front_undo(void)342da668aa1SThomas Huth static void test_discard_front_undo(void)
343da668aa1SThomas Huth {
344da668aa1SThomas Huth IOVDiscardUndo undo;
345da668aa1SThomas Huth struct iovec *iov;
346da668aa1SThomas Huth struct iovec *iov_tmp;
347da668aa1SThomas Huth struct iovec *iov_orig;
348da668aa1SThomas Huth unsigned int iov_cnt;
349da668aa1SThomas Huth unsigned int iov_cnt_tmp;
350da668aa1SThomas Huth size_t size;
351da668aa1SThomas Huth
352da668aa1SThomas Huth /* Discard zero bytes */
353da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
354c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
355da668aa1SThomas Huth iov_tmp = iov;
356da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
357da668aa1SThomas Huth iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, 0, &undo);
358da668aa1SThomas Huth iov_discard_undo(&undo);
359da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
360da668aa1SThomas Huth g_free(iov_orig);
361da668aa1SThomas Huth iov_free(iov, iov_cnt);
362da668aa1SThomas Huth
363da668aa1SThomas Huth /* Discard more bytes than vector size */
364da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
365c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
366da668aa1SThomas Huth iov_tmp = iov;
367da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
368da668aa1SThomas Huth size = iov_size(iov, iov_cnt);
369da668aa1SThomas Huth iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size + 1, &undo);
370da668aa1SThomas Huth iov_discard_undo(&undo);
371da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
372da668aa1SThomas Huth g_free(iov_orig);
373da668aa1SThomas Huth iov_free(iov, iov_cnt);
374da668aa1SThomas Huth
375da668aa1SThomas Huth /* Discard entire vector */
376da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
377c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
378da668aa1SThomas Huth iov_tmp = iov;
379da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
380da668aa1SThomas Huth size = iov_size(iov, iov_cnt);
381da668aa1SThomas Huth iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
382da668aa1SThomas Huth iov_discard_undo(&undo);
383da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
384da668aa1SThomas Huth g_free(iov_orig);
385da668aa1SThomas Huth iov_free(iov, iov_cnt);
386da668aa1SThomas Huth
387da668aa1SThomas Huth /* Discard within first element */
388da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
389c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
390da668aa1SThomas Huth iov_tmp = iov;
391da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
392da668aa1SThomas Huth size = g_test_rand_int_range(1, iov->iov_len);
393da668aa1SThomas Huth iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
394da668aa1SThomas Huth iov_discard_undo(&undo);
395da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
396da668aa1SThomas Huth g_free(iov_orig);
397da668aa1SThomas Huth iov_free(iov, iov_cnt);
398da668aa1SThomas Huth
399da668aa1SThomas Huth /* Discard entire first element */
400da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
401c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
402da668aa1SThomas Huth iov_tmp = iov;
403da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
404da668aa1SThomas Huth iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, iov->iov_len, &undo);
405da668aa1SThomas Huth iov_discard_undo(&undo);
406da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
407da668aa1SThomas Huth g_free(iov_orig);
408da668aa1SThomas Huth iov_free(iov, iov_cnt);
409da668aa1SThomas Huth
410da668aa1SThomas Huth /* Discard within second element */
411da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
412c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
413da668aa1SThomas Huth iov_tmp = iov;
414da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
415da668aa1SThomas Huth size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
416da668aa1SThomas Huth iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
417da668aa1SThomas Huth iov_discard_undo(&undo);
418da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
419da668aa1SThomas Huth g_free(iov_orig);
420da668aa1SThomas Huth iov_free(iov, iov_cnt);
421da668aa1SThomas Huth }
422da668aa1SThomas Huth
test_discard_back(void)423da668aa1SThomas Huth static void test_discard_back(void)
424da668aa1SThomas Huth {
425da668aa1SThomas Huth struct iovec *iov;
426da668aa1SThomas Huth unsigned int iov_cnt;
427da668aa1SThomas Huth unsigned int iov_cnt_tmp;
428da668aa1SThomas Huth void *old_base;
429da668aa1SThomas Huth size_t size;
430da668aa1SThomas Huth size_t ret;
431da668aa1SThomas Huth
432da668aa1SThomas Huth /* Discard zero bytes */
433da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
434da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
435da668aa1SThomas Huth ret = iov_discard_back(iov, &iov_cnt_tmp, 0);
436da668aa1SThomas Huth g_assert(ret == 0);
437da668aa1SThomas Huth g_assert(iov_cnt_tmp == iov_cnt);
438da668aa1SThomas Huth iov_free(iov, iov_cnt);
439da668aa1SThomas Huth
440da668aa1SThomas Huth /* Discard more bytes than vector size */
441da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
442da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
443da668aa1SThomas Huth size = iov_size(iov, iov_cnt);
444da668aa1SThomas Huth ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1);
445da668aa1SThomas Huth g_assert(ret == size);
446da668aa1SThomas Huth g_assert(iov_cnt_tmp == 0);
447da668aa1SThomas Huth iov_free(iov, iov_cnt);
448da668aa1SThomas Huth
449da668aa1SThomas Huth /* Discard entire vector */
450da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
451da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
452da668aa1SThomas Huth size = iov_size(iov, iov_cnt);
453da668aa1SThomas Huth ret = iov_discard_back(iov, &iov_cnt_tmp, size);
454da668aa1SThomas Huth g_assert(ret == size);
455da668aa1SThomas Huth g_assert(iov_cnt_tmp == 0);
456da668aa1SThomas Huth iov_free(iov, iov_cnt);
457da668aa1SThomas Huth
458da668aa1SThomas Huth /* Discard within last element */
459da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
460da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
461da668aa1SThomas Huth old_base = iov[iov_cnt - 1].iov_base;
462da668aa1SThomas Huth size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
463da668aa1SThomas Huth ret = iov_discard_back(iov, &iov_cnt_tmp, size);
464da668aa1SThomas Huth g_assert(ret == size);
465da668aa1SThomas Huth g_assert(iov_cnt_tmp == iov_cnt);
466da668aa1SThomas Huth g_assert(iov[iov_cnt - 1].iov_base == old_base);
467da668aa1SThomas Huth iov_free(iov, iov_cnt);
468da668aa1SThomas Huth
469da668aa1SThomas Huth /* Discard entire last element */
470da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
471da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
472da668aa1SThomas Huth old_base = iov[iov_cnt - 1].iov_base;
473da668aa1SThomas Huth size = iov[iov_cnt - 1].iov_len;
474da668aa1SThomas Huth ret = iov_discard_back(iov, &iov_cnt_tmp, size);
475da668aa1SThomas Huth g_assert(ret == size);
476da668aa1SThomas Huth g_assert(iov_cnt_tmp == iov_cnt - 1);
477da668aa1SThomas Huth iov_free(iov, iov_cnt);
478da668aa1SThomas Huth
479da668aa1SThomas Huth /* Discard within second-to-last element */
480da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
481da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
482da668aa1SThomas Huth old_base = iov[iov_cnt - 2].iov_base;
483da668aa1SThomas Huth size = iov[iov_cnt - 1].iov_len +
484da668aa1SThomas Huth g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
485da668aa1SThomas Huth ret = iov_discard_back(iov, &iov_cnt_tmp, size);
486da668aa1SThomas Huth g_assert(ret == size);
487da668aa1SThomas Huth g_assert(iov_cnt_tmp == iov_cnt - 1);
488da668aa1SThomas Huth g_assert(iov[iov_cnt - 2].iov_base == old_base);
489da668aa1SThomas Huth iov_free(iov, iov_cnt);
490da668aa1SThomas Huth }
491da668aa1SThomas Huth
test_discard_back_undo(void)492da668aa1SThomas Huth static void test_discard_back_undo(void)
493da668aa1SThomas Huth {
494da668aa1SThomas Huth IOVDiscardUndo undo;
495da668aa1SThomas Huth struct iovec *iov;
496da668aa1SThomas Huth struct iovec *iov_orig;
497da668aa1SThomas Huth unsigned int iov_cnt;
498da668aa1SThomas Huth unsigned int iov_cnt_tmp;
499da668aa1SThomas Huth size_t size;
500da668aa1SThomas Huth
501da668aa1SThomas Huth /* Discard zero bytes */
502da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
503c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
504da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
505da668aa1SThomas Huth iov_discard_back_undoable(iov, &iov_cnt_tmp, 0, &undo);
506da668aa1SThomas Huth iov_discard_undo(&undo);
507da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
508da668aa1SThomas Huth g_free(iov_orig);
509da668aa1SThomas Huth iov_free(iov, iov_cnt);
510da668aa1SThomas Huth
511da668aa1SThomas Huth /* Discard more bytes than vector size */
512da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
513c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
514da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
515da668aa1SThomas Huth size = iov_size(iov, iov_cnt);
516da668aa1SThomas Huth iov_discard_back_undoable(iov, &iov_cnt_tmp, size + 1, &undo);
517da668aa1SThomas Huth iov_discard_undo(&undo);
518da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
519da668aa1SThomas Huth g_free(iov_orig);
520da668aa1SThomas Huth iov_free(iov, iov_cnt);
521da668aa1SThomas Huth
522da668aa1SThomas Huth /* Discard entire vector */
523da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
524c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
525da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
526da668aa1SThomas Huth size = iov_size(iov, iov_cnt);
527da668aa1SThomas Huth iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
528da668aa1SThomas Huth iov_discard_undo(&undo);
529da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
530da668aa1SThomas Huth g_free(iov_orig);
531da668aa1SThomas Huth iov_free(iov, iov_cnt);
532da668aa1SThomas Huth
533da668aa1SThomas Huth /* Discard within last element */
534da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
535c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
536da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
537da668aa1SThomas Huth size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
538da668aa1SThomas Huth iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
539da668aa1SThomas Huth iov_discard_undo(&undo);
540da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
541da668aa1SThomas Huth g_free(iov_orig);
542da668aa1SThomas Huth iov_free(iov, iov_cnt);
543da668aa1SThomas Huth
544da668aa1SThomas Huth /* Discard entire last element */
545da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
546c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
547da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
548da668aa1SThomas Huth size = iov[iov_cnt - 1].iov_len;
549da668aa1SThomas Huth iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
550da668aa1SThomas Huth iov_discard_undo(&undo);
551da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
552da668aa1SThomas Huth g_free(iov_orig);
553da668aa1SThomas Huth iov_free(iov, iov_cnt);
554da668aa1SThomas Huth
555da668aa1SThomas Huth /* Discard within second-to-last element */
556da668aa1SThomas Huth iov_random(&iov, &iov_cnt);
557c4f8ce24SPhilippe Mathieu-Daudé iov_orig = g_memdup2(iov, sizeof(iov[0]) * iov_cnt);
558da668aa1SThomas Huth iov_cnt_tmp = iov_cnt;
559da668aa1SThomas Huth size = iov[iov_cnt - 1].iov_len +
560da668aa1SThomas Huth g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
561da668aa1SThomas Huth iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
562da668aa1SThomas Huth iov_discard_undo(&undo);
563da668aa1SThomas Huth assert(iov_equals(iov, iov_orig, iov_cnt));
564da668aa1SThomas Huth g_free(iov_orig);
565da668aa1SThomas Huth iov_free(iov, iov_cnt);
566da668aa1SThomas Huth }
567da668aa1SThomas Huth
main(int argc,char ** argv)568da668aa1SThomas Huth int main(int argc, char **argv)
569da668aa1SThomas Huth {
570da668aa1SThomas Huth g_test_init(&argc, &argv, NULL);
571da668aa1SThomas Huth g_test_rand_int();
572da668aa1SThomas Huth g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf);
573da668aa1SThomas Huth g_test_add_func("/basic/iov/io", test_io);
574da668aa1SThomas Huth g_test_add_func("/basic/iov/discard-front", test_discard_front);
575da668aa1SThomas Huth g_test_add_func("/basic/iov/discard-back", test_discard_back);
576da668aa1SThomas Huth g_test_add_func("/basic/iov/discard-front-undo", test_discard_front_undo);
577da668aa1SThomas Huth g_test_add_func("/basic/iov/discard-back-undo", test_discard_back_undo);
578da668aa1SThomas Huth return g_test_run();
579da668aa1SThomas Huth }
580