The branch main has been updated by glebius:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=eb338e2370b4644382e6404d7402bc05eef13e54

commit eb338e2370b4644382e6404d7402bc05eef13e54
Author:     Gleb Smirnoff <[email protected]>
AuthorDate: 2024-04-08 20:16:50 +0000
Commit:     Gleb Smirnoff <[email protected]>
CommitDate: 2024-04-08 20:16:50 +0000

    tests/unix_seqpacket: provide random data pumping test with MSG_EOR
    
    Allocate a big chunk of randomly initialized memory.  Send it to the peer
    in random sized chunks, throwing MSG_EOR at randomly initialized offsets.
    Receive into random sized chunks setting MSG_WAITALL randomly.  Check that
    MSG_EORs where they should be, check that MSG_WAITALL is abode, but
    overriden by MSG_EOR.  And finally memcmp() what we receive.
    
    Reviewed by:            asomers, tuexen
    Differential Revision:  https://reviews.freebsd.org/D43775
---
 tests/sys/kern/unix_seqpacket_test.c | 151 +++++++++++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)

diff --git a/tests/sys/kern/unix_seqpacket_test.c 
b/tests/sys/kern/unix_seqpacket_test.c
index ca3fcdef9e6a..d463ae9b3ce6 100644
--- a/tests/sys/kern/unix_seqpacket_test.c
+++ b/tests/sys/kern/unix_seqpacket_test.c
@@ -1,5 +1,8 @@
 /*-
+ *
+ * Copyright (c) 2024 Gleb Smirnoff <[email protected]>
  * Copyright (c) 2014 Spectra Logic Corporation. All rights reserved.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -27,7 +30,9 @@
 #include <fcntl.h>
 #include <pthread.h>
 #include <signal.h>
+#include <stdlib.h>
 #include <sys/socket.h>
+#include <sys/sysctl.h>
 #include <sys/un.h>
 
 #include <stdio.h>
@@ -1089,6 +1094,151 @@ ATF_TC_BODY(sendrecv_128k_nonblocking, tc)
        test_sendrecv_symmetric_buffers(128 * 1024, false);
 }
 
+ATF_TC(random_eor_and_waitall);
+ATF_TC_HEAD(random_eor_and_waitall, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test random sized send/recv with "
+           "randomly placed MSG_EOR and randomly applied MSG_WAITALL on "
+           "PF_UNIX/SOCK_SEQPACKET");
+}
+
+struct random_eor_params {
+       u_long recvspace;
+       char *sendbuf;
+       size_t *records;
+       u_int nrecords;
+       int sock;
+       u_short seed[6];
+};
+
+#define        RANDOM_TESTSIZE ((size_t)100 * 1024 * 1024)
+/* Below defines are factor of recvspace. */
+#define        RANDOM_MAXRECORD        10
+#define        RANDOM_SENDSIZE 2
+#define        RANDOM_RECVSIZE 4
+
+static void *
+sending_thread(void *arg)
+{
+       struct random_eor_params *params = arg;
+       size_t off = 0;
+       int eor = 0;
+
+       while (off < RANDOM_TESTSIZE) {
+               ssize_t len;
+               int flags;
+
+               len = nrand48(&params->seed[3]) %
+                   (RANDOM_SENDSIZE * params->recvspace);
+               if (off + len >= params->records[eor]) {
+                       len = params->records[eor] - off;
+                       flags = MSG_EOR;
+                       eor++;
+               } else
+                       flags = 0;
+               ATF_REQUIRE(send(params->sock, &params->sendbuf[off], len,
+                   flags) == len);
+               off += len;
+#ifdef DEBUG
+               printf("send %zd%s\n", off, flags ? " EOR" : "");
+#endif
+       }
+
+       return (NULL);
+}
+
+ATF_TC_BODY(random_eor_and_waitall, tc)
+{
+       struct random_eor_params params;
+       void *recvbuf;
+       pthread_t t;
+       size_t off;
+       int fd[2], eor;
+
+       arc4random_buf(params.seed, sizeof(params.seed));
+       printf("Using seed:");
+       for (u_int i = 0; i < (u_int)sizeof(params.seed)/sizeof(u_short); i++)
+               printf(" 0x%.4x,", params.seed[i]);
+       printf("\n");
+
+       ATF_REQUIRE((params.sendbuf = malloc(RANDOM_TESTSIZE)) != NULL);
+       for (u_int i = 0; i < RANDOM_TESTSIZE / (u_int )sizeof(long); i++)
+               ((long *)params.sendbuf)[i] = nrand48(&params.seed[0]);
+
+       ATF_REQUIRE(sysctlbyname("net.local.stream.recvspace",
+           &params.recvspace, &(size_t){sizeof(u_long)}, NULL, 0) != -1);
+       ATF_REQUIRE((recvbuf =
+           malloc(RANDOM_RECVSIZE * params.recvspace)) != NULL);
+
+       params.nrecords = 2 * RANDOM_TESTSIZE /
+           (RANDOM_MAXRECORD * params.recvspace);
+
+       ATF_REQUIRE((params.records =
+           malloc(params.nrecords * sizeof(size_t *))) != NULL);
+       off = 0;
+       for (u_int i = 0; i < params.nrecords; i++) {
+               off += 1 + nrand48(&params.seed[0]) %
+                   (RANDOM_MAXRECORD * params.recvspace);
+               if (off > RANDOM_TESTSIZE) {
+                       params.nrecords = i;
+                       break;
+               }
+               params.records[i] = off;
+       }
+       params.records[params.nrecords - 1] = RANDOM_TESTSIZE;
+
+       ATF_REQUIRE(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, fd) == 0);
+       params.sock = fd[0];
+       ATF_REQUIRE(pthread_create(&t, NULL, sending_thread, &params) == 0);
+
+       off = 0;
+       eor = 0;
+       while (off < RANDOM_TESTSIZE) {
+               struct iovec iov = {
+                       .iov_base = recvbuf,
+                       .iov_len = nrand48(&params.seed[0]) %
+                           (RANDOM_RECVSIZE * params.recvspace)
+               };
+               struct msghdr hdr = {
+                       .msg_iov = &iov,
+                       .msg_iovlen = 1,
+               };
+               size_t len;
+               int waitall = iov.iov_len & 0x1 ? MSG_WAITALL : 0;
+
+               len = recvmsg(fd[1], &hdr, waitall);
+               if (waitall && !(hdr.msg_flags & MSG_EOR))
+                       ATF_CHECK_EQ_MSG(len, iov.iov_len,
+                           "recvmsg(MSG_WAITALL): %zd, expected %zd",
+                           len, iov.iov_len);
+               if (off + len == params.records[eor]) {
+                       ATF_REQUIRE_MSG(hdr.msg_flags & MSG_EOR,
+                           "recvmsg(): expected EOR @ %zd", off + len);
+                       eor++;
+               } else {
+                       ATF_REQUIRE_MSG(off + len < params.records[eor],
+                           "recvmsg() past EOR: %zd, expected %zd",
+                           off + len, params.records[eor]);
+                       ATF_REQUIRE_MSG(!(hdr.msg_flags & MSG_EOR),
+                           "recvmsg() spurious EOR at %zd, expected %zd",
+                           off + len, params.records[eor]);
+               }
+               ATF_REQUIRE_MSG(0 == memcmp(params.sendbuf + off, recvbuf, len),
+                   "data corruption past %zd", off);
+               off += len;
+#ifdef DEBUG
+               printf("recv %zd%s %zd/%zd%s\n", off,
+                   (hdr.msg_flags & MSG_EOR) ?  " EOR" : "",
+                   len, iov.iov_len,
+                   waitall ? " WAITALL" : "");
+#endif
+       }
+
+       ATF_REQUIRE(pthread_join(t, NULL) == 0);
+       free(params.sendbuf);
+       free(recvbuf);
+       free(params.records);
+}
 
 /*
  * Main.
@@ -1142,6 +1292,7 @@ ATF_TP_ADD_TCS(tp)
        ATF_TP_ADD_TC(tp, pipe_8k_128k);
        ATF_TP_ADD_TC(tp, pipe_128k_8k);
        ATF_TP_ADD_TC(tp, pipe_128k_128k);
+       ATF_TP_ADD_TC(tp, random_eor_and_waitall);
 
        return atf_no_error();
 }

Reply via email to