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