passfd: give nicer error for recvfd at eof
[gnulib.git] / lib / passfd.c
index 5d4c6a7..5388ca5 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011 Free Software Foundation, Inc.
+/* Copyright (C) 2011-2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include <unistd.h>
 
 #include <sys/socket.h>
-#if HAVE_SYS_UN_H
-# include <sys/un.h>
-#endif
 
 #include "cloexec.h"
 
+/* The code that uses CMSG_FIRSTHDR is enabled on
+   Linux, Mac OS X, FreeBSD, OpenBSD, NetBSD, AIX, OSF/1, Cygwin.
+   The code that uses HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS is enabled on
+   HP-UX, IRIX, Solaris.  */
+
+/* MSG_CMSG_CLOEXEC is defined only on Linux, as of 2011.  */
 #ifndef MSG_CMSG_CLOEXEC
 # define MSG_CMSG_CLOEXEC 0
 #endif
 int
 sendfd (int sock, int fd)
 {
-  char send = 0;
+  char byte = 0;
   struct iovec iov;
   struct msghdr msg;
-# if HAVE_UNIXSOCKET_SCM_RIGHTS_BSD44_WAY
+# ifdef CMSG_FIRSTHDR
   struct cmsghdr *cmsg;
   char buf[CMSG_SPACE (sizeof fd)];
 # endif
 
   /* send at least one char */
   memset (&msg, 0, sizeof msg);
-  iov.iov_base = &send;
+  iov.iov_base = &byte;
   iov.iov_len = 1;
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_name = NULL;
   msg.msg_namelen = 0;
 
-# if HAVE_UNIXSOCKET_SCM_RIGHTS_BSD44_WAY
+# ifdef CMSG_FIRSTHDR
   msg.msg_control = buf;
   msg.msg_controllen = sizeof buf;
   cmsg = CMSG_FIRSTHDR (&msg);
@@ -72,7 +75,7 @@ sendfd (int sock, int fd)
   cmsg->cmsg_len = CMSG_LEN (sizeof fd);
   /* Initialize the payload: */
   memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);
-# elif HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY
+# elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
   msg.msg_accrights = &fd;
   msg.msg_accrightslen = sizeof fd;
 # else
@@ -98,16 +101,17 @@ sendfd (int sock _GL_UNUSED, int fd _GL_UNUSED)
 /* recvfd receives a file descriptor through the socket.
    The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>).
 
-   Return 0 on success, or -1 with errno set in case of error.
+   Return the fd on success, or -1 with errno set in case of error.
 */
 int
 recvfd (int sock, int flags)
 {
-  char recv = 0;
+  char byte = 0;
   struct iovec iov;
   struct msghdr msg;
   int fd = -1;
-# if HAVE_UNIXSOCKET_SCM_RIGHTS_BSD44_WAY
+  ssize_t len;
+# ifdef CMSG_FIRSTHDR
   struct cmsghdr *cmsg;
   char buf[CMSG_SPACE (sizeof fd)];
   int flags_recvmsg = flags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0;
@@ -121,14 +125,14 @@ recvfd (int sock, int flags)
 
   /* send at least one char */
   memset (&msg, 0, sizeof msg);
-  iov.iov_base = &recv;
+  iov.iov_base = &byte;
   iov.iov_len = 1;
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_name = NULL;
   msg.msg_namelen = 0;
 
-# if HAVE_UNIXSOCKET_SCM_RIGHTS_BSD44_WAY
+# ifdef CMSG_FIRSTHDR
   msg.msg_control = buf;
   msg.msg_controllen = sizeof buf;
   cmsg = CMSG_FIRSTHDR (&msg);
@@ -139,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;
     }
 
@@ -166,7 +171,7 @@ recvfd (int sock, int flags)
         }
     }
 
-# elif HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY
+# elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
   msg.msg_accrights = &fd;
   msg.msg_accrightslen = sizeof fd;
   if (recvmsg (sock, &msg, 0) < 0)