bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

possible recvfd() improvement


From: Eric Blake
Subject: possible recvfd() improvement
Date: Sat, 21 Dec 2013 00:27:46 -0700
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.2.0

I noticed that recvfd() fails with errno set to EACCES if the other end
of the socket has closed (such as if it calls _exit()); but "Permission
denied" as the strerror() message doesn't read very well.  Any
objections to a patch along these lines to give a nicer error message
"Transport endpoint is not connected"?  Or any better errno value to
use?  ECONNABORTED? ENOLINK?

diff --git i/ChangeLog w/ChangeLog
index 25b59e3..f608556 100644
--- i/ChangeLog
+++ w/ChangeLog
@@ -1,3 +1,8 @@
+2013-12-21  Eric Blake  <address@hidden>
+
+       passfd: give nicer error for recvfd at eof
+       * lib/passfd.c (recvfd): Fake ENOTCONN if other end closes early.
+
 2013-12-04  Eric Blake  <address@hidden>

        absolute-header: port to IBM Blue Gene compilers
diff --git i/lib/passfd.c w/lib/passfd.c
index 44a9de7..5388ca5 100644
--- i/lib/passfd.c
+++ w/lib/passfd.c
@@ -110,6 +110,7 @@ recvfd (int sock, int flags)
   struct iovec iov;
   struct msghdr msg;
   int fd = -1;
+  ssize_t len;
 # ifdef CMSG_FIRSTHDR
   struct cmsghdr *cmsg;
   char buf[CMSG_SPACE (sizeof fd)];
@@ -142,16 +143,17 @@ recvfd (int sock, int flags)
   memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);
   msg.msg_controllen = cmsg->cmsg_len;

-  if (recvmsg (sock, &msg, flags_recvmsg) < 0)
+  len = recvmsg (sock, &msg, flags_recvmsg);
+  if (len < 0)
     return -1;

   cmsg = CMSG_FIRSTHDR (&msg);
   /* be paranoiac */
-  if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd)
+  if (len == 0 || cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd)
       || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
     {
       /* fake errno: at end the file is not available */
-      errno = EACCES;
+      errno = len ? EACCES : ENOTCONN;
       return -1;
     }



Here's the crude program I tested with:

$ cat foo.c
#include <config.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include "passfd.h"

int main(void) {
    int fds[2];
    pid_t pid;
    int fd;
    int status;

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0)
        exit(1);
    pid = fork();
    if (pid < 0)
        exit(2);
    if (pid == 0) {
        sleep(3);
        _exit(127);
    }
    close(fds[1]);
    fd = recvfd(fds[0], 0);
    if (fd < 0) {
        perror("hi");
        exit(3);
    }
    if (waitpid(pid, &status, 0) != pid)
        exit(4);
    if (status)
        exit(5);
    exit(0);
}
$ gcc -o foo -Wall -I. -Ignulib/lib foo.c -g gnulib/lib/.libs/libgnu.a

for a project that was using the passlib module from gnulib.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]