/* code lifted from Stevens' APUE */

#include	<errno.h>		/* for definition of errno */
#include	<stdarg.h>		/* ANSI C header file */
#include	<sys/types.h>
#include	<sys/socket.h>
#include	<sys/uio.h>
#include	<string.h>
#include        <unistd.h>
#include	"pass_fd.h"

#if VARIANT_SVR4

int
s_pipe(int fd[2])
{
    return( pipe(fd) );
}

#elif defined(VARIANT_43BSD) || defined(VARIANT_44BSD)

int
s_pipe(int fd[2])
{
    return( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) );
}

#else

#error "Couldn't guess variant"

#endif


#if VARIANT_43BSD

int
send_fd(int clifd, int fd)
{
    struct iovec  iov[1];
    struct msghdr msg;
    char   buf[2];

    iov[0].iov_base = buf;
    iov[0].iov_len  = 2;
    msg.msg_iov     = iov;
    msg.msg_iovlen  = 1;
    msg.msg_name    = NULL;
    msg.msg_namelen = 0;

    if (fd < 0) {
	msg.msg_accrights    = NULL;
	msg.msg_accrightslen = 0;
	buf[1] = -fd;
	if (buf[1] == 0)
	    buf[1] = 1;
    } 
    else {
	msg.msg_accrights    = (caddr_t) &fd;
	msg.msg_accrightslen = sizeof(int);
	buf[1] = 0;
    }
    buf[0] = 0;

    if (sendmsg(clifd, &msg, 0) != 2)
	return(-1);
    
    return(0);
}

int
recv_fd(int servfd)
{
    int newfd, nread, status;
    char *ptr, buf[2];
    struct iovec  iov[1];
    struct msghdr msg;

    iov[0].iov_base = buf;
    iov[0].iov_len  = 2;
    msg.msg_iov     = iov;
    msg.msg_iovlen  = 1;
    msg.msg_name    = NULL;
    msg.msg_namelen = 0;
    msg.msg_accrights = (caddr_t) &newfd;
    msg.msg_accrightslen = sizeof(int);
    
    if ( (nread = recvmsg(servfd, &msg, 0)) <= 0)
	return(-1);
    
    return(newfd);/* descriptor, or -status */
}

#else 

/* based on code from Postfix 2.3.3 (vk) */

union {
  struct cmsghdr just_for_alignment;
  char    control[CMSG_SPACE(sizeof(int))];
} control_un;

int
send_fd(int over, int sendfd)
{
  struct iovec iov[1];
  struct msghdr msg;
  struct cmsghdr *cmptr;

  memset((char *) &msg, 0, sizeof(msg));

  msg.msg_control = control_un.control;
  msg.msg_controllen = CMSG_LEN(sizeof(sendfd));

  cmptr = CMSG_FIRSTHDR(&msg);
  cmptr->cmsg_len = CMSG_LEN(sizeof(sendfd));
  cmptr->cmsg_level = SOL_SOCKET;
  cmptr->cmsg_type = SCM_RIGHTS;
  *(int *) CMSG_DATA(cmptr) = sendfd;

  msg.msg_name = NULL;
  msg.msg_namelen = 0;

  iov[0].iov_base = "";
  iov[0].iov_len = 1;
  msg.msg_iov = iov;
  msg.msg_iovlen = 1;

  if (sendmsg(over, &msg, 0) < 0)
    return -1;
  return 0;
}

int 
recv_fd(int over)
{
    struct msghdr msg;
    struct iovec iov[1];
    char    buf[1];
    struct cmsghdr *cmptr;

    memset((char *) &msg, 0, sizeof(msg));
    msg.msg_control = control_un.control;
    msg.msg_controllen = CMSG_LEN(sizeof(int));

    msg.msg_name = 0;
    msg.msg_namelen = 0;

    iov[0].iov_base = buf;
    iov[0].iov_len = sizeof(buf);
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    if (recvmsg(over, &msg, 0) < 0)
	return (-1);

    if ((cmptr = CMSG_FIRSTHDR(&msg)) != 0
	&& cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
	if (cmptr->cmsg_level != SOL_SOCKET || cmptr->cmsg_type != SCM_RIGHTS)
	  return(-1);			    /* error */
	return (*(int *) CMSG_DATA(cmptr)); /* the file handle */
    } else
	return (-1);
}

#endif


syntax highlighted by Code2HTML, v. 0.9.1