diff --git a/README.md b/README.md index 0422910..92766f9 100644 --- a/README.md +++ b/README.md @@ -303,7 +303,7 @@ Can a file descriptor be passed without sending any data? And the answer is clearly "no" -- the file descriptor is not passed when no data are included in the write. -(update, 2019-5-8 from Yicholas Rishel) +(update, 2019-5-8 from Nicholas Rishel) This is true for SOCK_STREAM sockets, but for SOCK_SEQPACKET sockets, you *can* do zero-length writes and pass an fd. @@ -316,7 +316,7 @@ you *can* do zero-length writes and pass an fd. 2. failing to accept an fd in the receiver results in the fd being closed by the kernel. - 3. a file descriptor must be accompanied by some data. + 3. a file descriptor must be accompanied by some data if sent via stream. ## Make X pass file descriptors diff --git a/fdpass.c b/fdpass.c index 74ac148..e97cecd 100644 --- a/fdpass.c +++ b/fdpass.c @@ -37,10 +37,15 @@ sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd, int *nfdp) int nfd_passed, nfd; int i; int *fd_passed; + int type; + int length; iov.iov_base = buf; iov.iov_len = bufsize; + length = sizeof( int ); + getsockopt (sock, SOL_SOCKET, SO_TYPE, &type, &length); + msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; @@ -52,7 +57,7 @@ sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd, int *nfdp) perror ("recvmsg"); exit(1); } - if (size > 0 && pass.cmsghdr.cmsg_len > sizeof (struct cmsghdr)) { + if ((size > 0 || type == SOCK_SEQPACKET) && pass.cmsghdr.cmsg_len > sizeof (struct cmsghdr)) { if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) { fprintf (stderr, "control message truncated"); @@ -68,7 +73,6 @@ sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd, int *nfdp) pass.cmsghdr.cmsg_type); exit(1); } - nfd_passed = (pass.cmsghdr.cmsg_len - sizeof (struct cmsghdr)) / sizeof (int); fd_passed = (int *) CMSG_DATA(&pass.cmsghdr); diff --git a/zerowrite.c b/zerowrite.c index b7775c6..5c13119 100644 --- a/zerowrite.c +++ b/zerowrite.c @@ -25,17 +25,28 @@ child(int sock) ssize_t size; sleep(1); - for (;;) { - nfd = 1; - size = sock_fd_read(sock, buf, sizeof(buf), &fd, &nfd); - if (size <= 0) - break; - printf ("read %d nfd %d\n", size, nfd); - if (nfd == 1) { - write(fd, "hello, world\n", 13); - close(fd); - } + size = sock_fd_read(sock, buf, sizeof(buf), NULL, NULL); + if (size <= 0) { + printf ("<=0"); + return; } + printf ("read %d\n", size); + + nfd = 1; + size = sock_fd_read(sock, buf, sizeof(buf), &fd, &nfd); + printf ("read %d nfd %d\n", size, nfd); + if (nfd == 1) { + write(fd, "hello, world\n", 13); + close(fd); + } + + + size = sock_fd_read(sock, buf, sizeof(buf), NULL, NULL); + if (size <= 0) { + printf ("<=0"); + return; + } + printf ("read %d\n", size); } void @@ -60,7 +71,7 @@ main(int argc, char **argv) int sv[2]; int pid; - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) { + if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, sv) < 0) { perror("socketpair"); exit(1); }