-/* $OpenBSD: ungc.c,v 1.2 2021/12/15 21:25:55 bluhm Exp $ */
+/* $OpenBSD: ungc.c,v 1.3 2022/01/11 08:03:25 mvs Exp $ */
/*
* Copyright (c) 2021 Vitaliy Makkoveev <mvs@openbsd.org>
struct iovec iov;
struct msghdr msgh;
struct cmsghdr *cmsgh;
- int s[2];
+ int sp[2], sl[2], ts;
int infinite = 0;
if (argc > 1 && !strcmp(argv[1], "--infinite"))
err(1, "clock_gettime");
while (1) {
- if (socketpair(AF_UNIX, SOCK_STREAM|O_NONBLOCK, 0, s) < 0)
+ if (socketpair(AF_UNIX, SOCK_STREAM|O_NONBLOCK, 0, sp) < 0)
+ err(1, "socketpair");
+
+ iov_buf = 0;
+ iov.iov_base = &iov_buf;
+ iov.iov_len = sizeof(iov_buf);
+ msgh.msg_control = msg_control.control;
+ msgh.msg_controllen = sizeof(msg_control.control);
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_name = NULL;
+ msgh.msg_namelen = 0;
+ cmsgh = CMSG_FIRSTHDR(&msgh);
+ cmsgh->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsgh->cmsg_level = SOL_SOCKET;
+ cmsgh->cmsg_type = SCM_RIGHTS;
+
+ *((int *)CMSG_DATA(cmsgh)) = sp[0];
+
+ if (sendmsg(sp[0], &msgh, 0) < 0) {
+ if (errno == EMFILE) {
+ /* Too may sockets in flight */
+ close(sp[0]);
+ goto skip;
+ }
+
+ err(1, "sendmsg");
+ }
+
+ *((int *)CMSG_DATA(cmsgh)) = sp[1];
+
+ if (sendmsg(sp[1], &msgh, 0) < 0) {
+ if (errno == EMFILE) {
+ /* Too may sockets in flight */
+ close(sp[0]);
+ goto skip;
+ }
+
+ err(1, "sendmsg");
+ }
+
+ /*
+ * After following close(2), the sp[0] socket has
+ * f_count equal to unp_msgcount. This socket is not
+ * in the loop and should not be killed by unp_gc().
+ * This sockets should be successfully received.
+ * The sp[1] socket is stored within sp[0] receive
+ * buffer. This socket should be also successfully
+ * received.
+ */
+
+ close(sp[0]);
+
+ if (socketpair(AF_UNIX, SOCK_STREAM|O_NONBLOCK, 0, sl) < 0)
err(1, "socketpair");
iov_buf = 0;
cmsgh->cmsg_len = CMSG_LEN(sizeof(int) * 2);
cmsgh->cmsg_level = SOL_SOCKET;
cmsgh->cmsg_type = SCM_RIGHTS;
- *((int *)CMSG_DATA(cmsgh) + 0) = s[0];
- *((int *)CMSG_DATA(cmsgh) + 1) = s[1];
+ *((int *)CMSG_DATA(cmsgh) + 0) = sl[0];
+ *((int *)CMSG_DATA(cmsgh) + 1) = sl[1];
- if (sendmsg(s[0], &msgh, 0) < 0) {
+ if (sendmsg(sl[0], &msgh, 0) < 0) {
if (errno != EMFILE)
err(1, "sendmsg");
}
- close(s[0]);
- close(s[1]);
+ /*
+ * After following close(2), the sl[0] socket is not
+ * in the loop and should be disposed by sorflush().
+ * The sl[1] socket is in the loop and should be
+ * killed by unp_gc().
+ */
+
+ close(sl[0]);
+ close(sl[1]);
+
+ if (recvmsg(sp[1], &msgh, 0) < 0) {
+ if (errno == EMSGSIZE)
+ goto skip;
+ err(1, "recvmsg");
+ }
+
+ if (!(cmsgh = CMSG_FIRSTHDR(&msgh)))
+ errx(1, "bad cmsg header");
+ if (cmsgh->cmsg_level != SOL_SOCKET)
+ errx(1, "bad cmsg level");
+ if (cmsgh->cmsg_type != SCM_RIGHTS)
+ errx(1, "bad cmsg type");
+ if (cmsgh->cmsg_len != CMSG_LEN(sizeof(ts)))
+ errx(1, "bad cmsg length");
+
+ ts = *((int *)CMSG_DATA(cmsgh));
+
+ if (recvmsg(ts, &msgh, 0) < 0) {
+ if (errno == EMSGSIZE)
+ goto skip;
+ err(1, "recvmsg");
+ }
+
+ close(ts);
+
+ if (!(cmsgh = CMSG_FIRSTHDR(&msgh)))
+ errx(1, "bad cmsg header");
+ if (cmsgh->cmsg_level != SOL_SOCKET)
+ errx(1, "bad cmsg level");
+ if (cmsgh->cmsg_type != SCM_RIGHTS)
+ errx(1, "bad cmsg type");
+ if (cmsgh->cmsg_len != CMSG_LEN(sizeof(ts)))
+ errx(1, "bad cmsg length");
+
+ ts = *((int *)CMSG_DATA(cmsgh));
+ close(ts);
+
+skip:
+ close(sp[1]);
if (!infinite) {
if (clock_gettime(CLOCK_BOOTTIME, &ts_now) <0)