changeset 14421:f23a6a383241

passfd module, part 3. * lib/passfd.h (recvfd): Add a flags argument. * lib/passfd.c: Include <fcntl.h>, cloexec.h. (recvfd): Add a flags argument. * m4/afunix.m4 (gl_SOCKET_AFUNIX): Test whether MSG_CMSG_CLOEXEC exists. * modules/passfd (Depends-on): Add cloexec. Suggested by Eric Blake.
author Bastien Roucariès <roucaries.bastien@gmail.com>
date Sun, 13 Mar 2011 16:36:30 +0100
parents 08622275f761
children e29883807ecf
files ChangeLog lib/passfd.c lib/passfd.h m4/afunix.m4 modules/passfd
diffstat 5 files changed, 89 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2011-03-13  Bastien Roucariès  <roucaries.bastien@gmail.com>
+            Bruno Haible  <bruno@clisp.org>
+
+	passfd module, part 3.
+	* lib/passfd.h (recvfd): Add a flags argument.
+	* lib/passfd.c: Include <fcntl.h>, cloexec.h.
+	(recvfd): Add a flags argument.
+	* m4/afunix.m4 (gl_SOCKET_AFUNIX): Test whether MSG_CMSG_CLOEXEC
+	exists.
+	* modules/passfd (Depends-on): Add cloexec.
+	Suggested by Eric Blake.
+
 2011-03-13  Bruno Haible  <bruno@clisp.org>
 
 	passfd module, part 2, tweaks.
--- a/lib/passfd.c
+++ b/lib/passfd.c
@@ -19,6 +19,7 @@
 #include "passfd.h"
 
 #include <errno.h>
+#include <fcntl.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
@@ -30,6 +31,8 @@
 # include <sys/un.h>
 #endif
 
+#include "cloexec.h"
+
 /* sendfd sends the file descriptor fd along the socket
    to a process calling recvfd on the other end.
 
@@ -79,16 +82,23 @@
 }
 
 /* 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.
 */
 int
-recvfd (int sock)
+recvfd (int sock, int flags)
 {
   char recv = 0;
   struct iovec iov[1];
   struct msghdr msg;
 
+  if ((flags & ~O_CLOEXEC) != 0)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
   /* send at least one char */
   iov[0].iov_base = &recv;
   iov[0].iov_len = 1;
@@ -103,6 +113,11 @@
     struct cmsghdr *cmsg;
     char buf[CMSG_SPACE (sizeof (fd))];
     const int mone = -1;
+# if HAVE_MSG_CMSG_CLOEXEC
+    int flags_recvmsg = (flags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0);
+# else
+    int flags_recvmsg = 0;
+# endif
 
     msg.msg_control = buf;
     msg.msg_controllen = sizeof (buf);
@@ -114,7 +129,7 @@
     memcpy (CMSG_DATA (cmsg), &mone, sizeof (mone));
     msg.msg_controllen = cmsg->cmsg_len;
 
-    if (recvmsg (sock, &msg, 0) < 0)
+    if (recvmsg (sock, &msg, flags_recvmsg) < 0)
       return -1;
 
     cmsg = CMSG_FIRSTHDR (&msg);
@@ -128,7 +143,23 @@
       }
 
     memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd));
+
+# if !HAVE_MSG_CMSG_CLOEXEC
+    /* set close-on-exec flag */
+    if (flags & O_CLOEXEC)
+      {
+        if (set_cloexec_flag (fd, true) < 0)
+          {
+            int saved_errno = errno;
+            (void) close (fd);
+            errno = saved_errno;
+            return -1;
+          }
+      }
+# endif
+
     return fd;
+
 #elif HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY
     int fd;
 
@@ -136,7 +167,21 @@
     msg.msg_accrightslen = sizeof (fd);
     if (recvmsg (sock, &msg, 0) < 0)
       return -1;
+
+    /* set close-on-exec flag */
+    if (flags & O_CLOEXEC)
+      {
+        if (set_cloexec_flag (fd, true) < 0)
+          {
+            int saved_errno = errno;
+            (void) close (fd);
+            errno = saved_errno;
+            return -1;
+          }
+      }
+
     return fd;
+
 #else
     errno = ENOSYS;
     return -1;
--- a/lib/passfd.h
+++ b/lib/passfd.h
@@ -23,7 +23,7 @@
 #endif
 
 extern int sendfd (int sock, int fd);
-extern int recvfd (int sock);
+extern int recvfd (int sock, int flags);
 
 #ifdef __cplusplus
 }
--- a/m4/afunix.m4
+++ b/m4/afunix.m4
@@ -1,4 +1,4 @@
-# afunix.m4 serial 2
+# afunix.m4 serial 3
 dnl Copyright (C) 2011 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -109,4 +109,31 @@
     AC_DEFINE([HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY], [1],
       [Define to 1 if fd can be sent/received in the BSD4.3 way.])
   fi
+
+  AC_MSG_CHECKING([for UNIX domain sockets recvmsg() MSG_CMSG_CLOEXEC flag])
+  AC_CACHE_VAL([gl_cv_socket_unix_msg_cmsg_cloexec],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <sys/types.h>
+            #ifdef HAVE_SYS_SOCKET_H
+            #include <sys/socket.h>
+            #endif
+            #ifdef HAVE_SYS_UN_H
+            #include <sys/un.h>
+            #endif
+            #ifdef HAVE_WINSOCK2_H
+            #include <winsock2.h>
+            #endif
+            ]],
+            [[int flags = MSG_CMSG_CLOEXEC;
+              if (&flags) return 0;
+            ]])],
+       [gl_cv_socket_unix_msg_cmsg_cloexec=yes],
+       [gl_cv_socket_unix_msg_cmsg_cloexec=no])
+    ])
+  AC_MSG_RESULT([$gl_cv_socket_unix_msg_cmsg_cloexec])
+  if test $gl_cv_socket_unix_msg_cmsg_cloexec = yes; then
+    AC_DEFINE([HAVE_MSG_CMSG_CLOEXEC], [1],
+      [Define to 1 if recvmsg could be specified with MSG_CMSG_CLOEXEC.])
+  fi
 ])
--- a/modules/passfd
+++ b/modules/passfd
@@ -8,6 +8,7 @@
 m4/sockpfaf.m4
 
 Depends-on:
+cloexec
 sys_socket
 extensions