The branch main has been updated by glebius:

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

commit bc7ee0b52a8dd613711c7225244aac954b41e534
Author:     Gleb Smirnoff <gleb...@freebsd.org>
AuthorDate: 2025-02-10 21:53:41 +0000
Commit:     Gleb Smirnoff <gleb...@freebsd.org>
CommitDate: 2025-02-10 22:01:16 +0000

    tests/unix_stream: add test that checks a full socket isn't writable
---
 tests/sys/kern/unix_stream.c | 86 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 81 insertions(+), 5 deletions(-)

diff --git a/tests/sys/kern/unix_stream.c b/tests/sys/kern/unix_stream.c
index d57cfad020fa..49aabdaa0943 100644
--- a/tests/sys/kern/unix_stream.c
+++ b/tests/sys/kern/unix_stream.c
@@ -26,14 +26,15 @@
  */
 
 #include <sys/cdefs.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <signal.h>
 #include <sys/socket.h>
+#include <sys/event.h>
+#include <sys/sysctl.h>
 #include <sys/un.h>
-
+#include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <poll.h>
 
 #include <atf-c.h>
 
@@ -49,6 +50,18 @@ do_socketpair(int *sv)
        ATF_REQUIRE(sv[0] != sv[1]);
 }
 
+static u_long
+getsendspace(void)
+{
+       u_long sendspace;
+
+       ATF_REQUIRE_MSG(sysctlbyname("net.local.stream.sendspace", &sendspace,
+           &(size_t){sizeof(u_long)}, NULL, 0) != -1,
+           "sysctl net.local.stream.sendspace failed: %s", strerror(errno));
+
+       return (sendspace);
+}
+
 /* getpeereid(3) should work with stream sockets created via socketpair(2) */
 ATF_TC_WITHOUT_HEAD(getpeereid);
 ATF_TC_BODY(getpeereid, tc)
@@ -86,11 +99,74 @@ ATF_TC_BODY(send_0, tc)
        close(sv[1]);
 }
 
+static void
+check_writable(int fd, int expect)
+{
+       fd_set wrfds;
+       struct pollfd pfd[1];
+       struct kevent kev;
+       int nfds, kq;
+
+       FD_ZERO(&wrfds);
+       FD_SET(fd, &wrfds);
+       nfds = select(fd + 1, NULL, &wrfds, NULL,
+           &(struct timeval){.tv_usec = 1000});
+       ATF_REQUIRE_MSG(nfds == expect,
+           "select() returns %d errno %d", nfds, errno);
+
+       pfd[0] = (struct pollfd){
+               .fd = fd,
+               .events = POLLOUT | POLLWRNORM,
+       };
+       nfds = poll(pfd, 1, 1);
+       ATF_REQUIRE_MSG(nfds == expect,
+           "poll() returns %d errno %d", nfds, errno);
+
+       ATF_REQUIRE(kq = kqueue());
+       EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+       ATF_REQUIRE(kevent(kq, &kev, 1, NULL, 0, NULL) == 0);
+       nfds = kevent(kq, NULL, 0, &kev, 1,
+           &(struct timespec){.tv_nsec = 1000000});
+       ATF_REQUIRE_MSG(nfds == expect,
+               "kevent() returns %d errno %d", nfds, errno);
+       close(kq);
+}
+
+/*
+ * Make sure that a full socket is not reported as writable by event APIs.
+ */
+ATF_TC_WITHOUT_HEAD(full_not_writable);
+ATF_TC_BODY(full_not_writable, tc)
+{
+       void *buf;
+       u_long sendspace;
+       int sv[2];
+
+       sendspace = getsendspace();
+       ATF_REQUIRE((buf = malloc(sendspace)) != NULL);
+       do_socketpair(sv);
+       ATF_REQUIRE(fcntl(sv[0], F_SETFL, O_NONBLOCK) != -1);
+       do {} while (send(sv[0], buf, sendspace, 0) == (ssize_t)sendspace);
+       ATF_REQUIRE(errno == EAGAIN);
+       ATF_REQUIRE(fcntl(sv[0], F_SETFL, 0) != -1);
+
+       check_writable(sv[0], 0);
+
+       /* Read some data and re-check. */
+       ATF_REQUIRE(read(sv[1], buf, sendspace / 2) == sendspace / 2);
+
+       check_writable(sv[0], 1);
+
+       free(buf);
+       close(sv[0]);
+       close(sv[1]);
+}
 
 ATF_TP_ADD_TCS(tp)
 {
        ATF_TP_ADD_TC(tp, getpeereid);
        ATF_TP_ADD_TC(tp, send_0);
+       ATF_TP_ADD_TC(tp, full_not_writable);
 
        return atf_no_error();
 }

Reply via email to