Edit

kc3-lang/gnulib/lib/passfd.c

Branch :

  • Show log

    Commit

  • Author : Bruno Haible
    Date : 2011-04-30 14:05:52
    Hash : 89d10938
    Message : passfd: Add comments. * lib/passfd.c: Add comments about platforms.

  • lib/passfd.c
  • /* Copyright (C) 2011 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
       the Free Software Foundation; either version 3 of the License, or
       (at your option) any later version.
    
       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.
    
       You should have received a copy of the GNU General Public License
       along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
    
    #include <config.h>
    
    /* Specification.  */
    #include "passfd.h"
    
    #include <errno.h>
    #include <fcntl.h>
    #include <stddef.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    #include <sys/socket.h>
    
    #include "cloexec.h"
    
    /* The code that uses CMSG_FIRSTHDR is enabled on
       Linux, MacOS 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
    
    #if HAVE_SENDMSG
    /* sendfd sends the file descriptor fd along the socket
       to a process calling recvfd on the other end.
    
       Return 0 on success, or -1 with errno set in case of error.
    */
    int
    sendfd (int sock, int fd)
    {
      char byte = 0;
      struct iovec iov;
      struct msghdr msg;
    # 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 = &byte;
      iov.iov_len = 1;
      msg.msg_iov = &iov;
      msg.msg_iovlen = 1;
      msg.msg_name = NULL;
      msg.msg_namelen = 0;
    
    # ifdef CMSG_FIRSTHDR
      msg.msg_control = buf;
      msg.msg_controllen = sizeof buf;
      cmsg = CMSG_FIRSTHDR (&msg);
      cmsg->cmsg_level = SOL_SOCKET;
      cmsg->cmsg_type = SCM_RIGHTS;
      cmsg->cmsg_len = CMSG_LEN (sizeof fd);
      /* Initialize the payload: */
      memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);
    # elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
      msg.msg_accrights = &fd;
      msg.msg_accrightslen = sizeof fd;
    # else
      errno = ENOSYS;
      return -1;
    # endif
    
      if (sendmsg (sock, &msg, 0) != iov.iov_len)
        return -1;
      return 0;
    }
    #else
    int
    sendfd (int sock _GL_UNUSED, int fd _GL_UNUSED)
    {
      errno = ENOSYS;
      return -1;
    }
    #endif
    
    
    #if HAVE_RECVMSG
    /* 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, int flags)
    {
      char byte = 0;
      struct iovec iov;
      struct msghdr msg;
      int fd = -1;
    # ifdef CMSG_FIRSTHDR
      struct cmsghdr *cmsg;
      char buf[CMSG_SPACE (sizeof fd)];
      int flags_recvmsg = flags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0;
    # endif
    
      if ((flags & ~O_CLOEXEC) != 0)
        {
          errno = EINVAL;
          return -1;
        }
    
      /* send at least one char */
      memset (&msg, 0, sizeof msg);
      iov.iov_base = &byte;
      iov.iov_len = 1;
      msg.msg_iov = &iov;
      msg.msg_iovlen = 1;
      msg.msg_name = NULL;
      msg.msg_namelen = 0;
    
    # ifdef CMSG_FIRSTHDR
      msg.msg_control = buf;
      msg.msg_controllen = sizeof buf;
      cmsg = CMSG_FIRSTHDR (&msg);
      cmsg->cmsg_level = SOL_SOCKET;
      cmsg->cmsg_type = SCM_RIGHTS;
      cmsg->cmsg_len = CMSG_LEN (sizeof fd);
      /* Initialize the payload: */
      memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);
      msg.msg_controllen = cmsg->cmsg_len;
    
      if (recvmsg (sock, &msg, flags_recvmsg) < 0)
        return -1;
    
      cmsg = CMSG_FIRSTHDR (&msg);
      /* be paranoiac */
      if (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;
          return -1;
        }
    
      memcpy (&fd, CMSG_DATA (cmsg), sizeof fd);
    
      /* set close-on-exec flag */
      if (!MSG_CMSG_CLOEXEC && (flags & O_CLOEXEC))
        {
          if (set_cloexec_flag (fd, true) < 0)
            {
              int saved_errno = errno;
              (void) close (fd);
              errno = saved_errno;
              return -1;
            }
        }
    
    # elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
      msg.msg_accrights = &fd;
      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;
              close (fd);
              errno = saved_errno;
              return -1;
            }
        }
    # else
      errno = ENOSYS;
    # endif
    
      return fd;
    }
    #else
    int
    recvfd (int sock _GL_UNUSED, int flags _GL_UNUSED)
    {
      errno = ENOSYS;
      return -1;
    }
    #endif