qemu/tests/unit/test-iov.c
<<
>>
Prefs
   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 */
   6static 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
  19static 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
  28static 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
  34static 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
  60static 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
 145static 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
 153static 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
 261static 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
 340static 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
 421static 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
 490static 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
 566int 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