qemu/tests/test-iov.c
<<
>>
Prefs
   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 */
   7static 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
  20static 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
  29static 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
  55static 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, -1);
  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, -1);
  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, -1);
  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, -1);
 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
 140static 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
 148static 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_malloc(sizeof(*iov) * niov);
 171    memcpy(siov, iov, sizeof(*iov) * niov);
 172
 173    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
 174       perror("socketpair");
 175       exit(1);
 176    }
 177
 178    FD_ZERO(&fds);
 179
 180    t = 0;
 181    if (fork() == 0) {
 182       /* writer */
 183
 184       close(sv[0]);
 185       FD_SET(sv[1], &fds);
 186       fcntl(sv[1], F_SETFL, O_RDWR|O_NONBLOCK);
 187       r = g_test_rand_int_range(sz / 2, sz);
 188       setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r));
 189
 190       for (i = 0; i <= sz; ++i) {
 191           for (j = i; j <= sz; ++j) {
 192               k = i;
 193               do {
 194                   s = g_test_rand_int_range(0, j - k + 1);
 195                   r = iov_send(sv[1], iov, niov, k, s);
 196                   g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
 197                   if (r >= 0) {
 198                       k += r;
 199                       t += r;
 200                       usleep(g_test_rand_int_range(0, 30));
 201                   } else if (errno == EAGAIN) {
 202                       select(sv[1]+1, NULL, &fds, NULL, NULL);
 203                       continue;
 204                   } else {
 205                       perror("send");
 206                       exit(1);
 207                   }
 208               } while(k < j);
 209           }
 210       }
 211       iov_free(iov, niov);
 212       g_free(buf);
 213       g_free(siov);
 214       exit(0);
 215
 216    } else {
 217       /* reader & verifier */
 218
 219       close(sv[1]);
 220       FD_SET(sv[0], &fds);
 221       fcntl(sv[0], F_SETFL, O_RDWR|O_NONBLOCK);
 222       r = g_test_rand_int_range(sz / 2, sz);
 223       setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r));
 224       usleep(500000);
 225
 226       for (i = 0; i <= sz; ++i) {
 227           for (j = i; j <= sz; ++j) {
 228               k = i;
 229               iov_memset(iov, niov, 0, 0xff, -1);
 230               do {
 231                   s = g_test_rand_int_range(0, j - k + 1);
 232                   r = iov_recv(sv[0], iov, niov, k, s);
 233                   g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
 234                   if (r > 0) {
 235                       k += r;
 236                       t += r;
 237                   } else if (!r) {
 238                       if (s) {
 239                           break;
 240                       }
 241                   } else if (errno == EAGAIN) {
 242                       select(sv[0]+1, &fds, NULL, NULL, NULL);
 243                       continue;
 244                   } else {
 245                       perror("recv");
 246                       exit(1);
 247                   }
 248               } while(k < j);
 249               test_iov_bytes(iov, niov, i, j - i);
 250           }
 251        }
 252
 253       iov_free(iov, niov);
 254       g_free(buf);
 255       g_free(siov);
 256     }
 257#endif
 258}
 259
 260static void test_discard_front(void)
 261{
 262    struct iovec *iov;
 263    struct iovec *iov_tmp;
 264    unsigned int iov_cnt;
 265    unsigned int iov_cnt_tmp;
 266    void *old_base;
 267    size_t size;
 268    size_t ret;
 269
 270    /* Discard zero bytes */
 271    iov_random(&iov, &iov_cnt);
 272    iov_tmp = iov;
 273    iov_cnt_tmp = iov_cnt;
 274    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, 0);
 275    g_assert(ret == 0);
 276    g_assert(iov_tmp == iov);
 277    g_assert(iov_cnt_tmp == iov_cnt);
 278    iov_free(iov, iov_cnt);
 279
 280    /* Discard more bytes than vector size */
 281    iov_random(&iov, &iov_cnt);
 282    iov_tmp = iov;
 283    iov_cnt_tmp = iov_cnt;
 284    size = iov_size(iov, iov_cnt);
 285    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size + 1);
 286    g_assert(ret == size);
 287    g_assert(iov_cnt_tmp == 0);
 288    iov_free(iov, iov_cnt);
 289
 290    /* Discard entire vector */
 291    iov_random(&iov, &iov_cnt);
 292    iov_tmp = iov;
 293    iov_cnt_tmp = iov_cnt;
 294    size = iov_size(iov, iov_cnt);
 295    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
 296    g_assert(ret == size);
 297    g_assert(iov_cnt_tmp == 0);
 298    iov_free(iov, iov_cnt);
 299
 300    /* Discard within first element */
 301    iov_random(&iov, &iov_cnt);
 302    iov_tmp = iov;
 303    iov_cnt_tmp = iov_cnt;
 304    old_base = iov->iov_base;
 305    size = g_test_rand_int_range(1, iov->iov_len);
 306    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
 307    g_assert(ret == size);
 308    g_assert(iov_tmp == iov);
 309    g_assert(iov_cnt_tmp == iov_cnt);
 310    g_assert(iov_tmp->iov_base == old_base + size);
 311    iov_tmp->iov_base = old_base; /* undo before g_free() */
 312    iov_free(iov, iov_cnt);
 313
 314    /* Discard entire first element */
 315    iov_random(&iov, &iov_cnt);
 316    iov_tmp = iov;
 317    iov_cnt_tmp = iov_cnt;
 318    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, iov->iov_len);
 319    g_assert(ret == iov->iov_len);
 320    g_assert(iov_tmp == iov + 1);
 321    g_assert(iov_cnt_tmp == iov_cnt - 1);
 322    iov_free(iov, iov_cnt);
 323
 324    /* Discard within second element */
 325    iov_random(&iov, &iov_cnt);
 326    iov_tmp = iov;
 327    iov_cnt_tmp = iov_cnt;
 328    old_base = iov[1].iov_base;
 329    size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
 330    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
 331    g_assert(ret == size);
 332    g_assert(iov_tmp == iov + 1);
 333    g_assert(iov_cnt_tmp == iov_cnt - 1);
 334    g_assert(iov_tmp->iov_base == old_base + (size - iov->iov_len));
 335    iov_tmp->iov_base = old_base; /* undo before g_free() */
 336    iov_free(iov, iov_cnt);
 337}
 338
 339static void test_discard_back(void)
 340{
 341    struct iovec *iov;
 342    unsigned int iov_cnt;
 343    unsigned int iov_cnt_tmp;
 344    void *old_base;
 345    size_t size;
 346    size_t ret;
 347
 348    /* Discard zero bytes */
 349    iov_random(&iov, &iov_cnt);
 350    iov_cnt_tmp = iov_cnt;
 351    ret = iov_discard_back(iov, &iov_cnt_tmp, 0);
 352    g_assert(ret == 0);
 353    g_assert(iov_cnt_tmp == iov_cnt);
 354    iov_free(iov, iov_cnt);
 355
 356    /* Discard more bytes than vector size */
 357    iov_random(&iov, &iov_cnt);
 358    iov_cnt_tmp = iov_cnt;
 359    size = iov_size(iov, iov_cnt);
 360    ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1);
 361    g_assert(ret == size);
 362    g_assert(iov_cnt_tmp == 0);
 363    iov_free(iov, iov_cnt);
 364
 365    /* Discard entire vector */
 366    iov_random(&iov, &iov_cnt);
 367    iov_cnt_tmp = iov_cnt;
 368    size = iov_size(iov, iov_cnt);
 369    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
 370    g_assert(ret == size);
 371    g_assert(iov_cnt_tmp == 0);
 372    iov_free(iov, iov_cnt);
 373
 374    /* Discard within last element */
 375    iov_random(&iov, &iov_cnt);
 376    iov_cnt_tmp = iov_cnt;
 377    old_base = iov[iov_cnt - 1].iov_base;
 378    size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
 379    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
 380    g_assert(ret == size);
 381    g_assert(iov_cnt_tmp == iov_cnt);
 382    g_assert(iov[iov_cnt - 1].iov_base == old_base);
 383    iov_free(iov, iov_cnt);
 384
 385    /* Discard entire last element */
 386    iov_random(&iov, &iov_cnt);
 387    iov_cnt_tmp = iov_cnt;
 388    old_base = iov[iov_cnt - 1].iov_base;
 389    size = iov[iov_cnt - 1].iov_len;
 390    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
 391    g_assert(ret == size);
 392    g_assert(iov_cnt_tmp == iov_cnt - 1);
 393    iov_free(iov, iov_cnt);
 394
 395    /* Discard within second-to-last element */
 396    iov_random(&iov, &iov_cnt);
 397    iov_cnt_tmp = iov_cnt;
 398    old_base = iov[iov_cnt - 2].iov_base;
 399    size = iov[iov_cnt - 1].iov_len +
 400           g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
 401    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
 402    g_assert(ret == size);
 403    g_assert(iov_cnt_tmp == iov_cnt - 1);
 404    g_assert(iov[iov_cnt - 2].iov_base == old_base);
 405    iov_free(iov, iov_cnt);
 406}
 407
 408int main(int argc, char **argv)
 409{
 410    g_test_init(&argc, &argv, NULL);
 411    g_test_rand_int();
 412    g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf);
 413    g_test_add_func("/basic/iov/io", test_io);
 414    g_test_add_func("/basic/iov/discard-front", test_discard_front);
 415    g_test_add_func("/basic/iov/discard-back", test_discard_back);
 416    return g_test_run();
 417}
 418