/* Public domain. */

#include <stdlib.h> /* some CMSG_* implementations require NULL */
#include <sys/types.h>
#include <sys/socket.h>
#include "socket_passfd.h"
#include "byte.h"
#include "error.h"

int socket_passfd(int s, int fd) {
  struct msghdr msg;
  struct cmsghdr* cmsg;
  char buf[CMSG_SPACE(sizeof fd)];

  cmsg = (struct cmsghdr *)buf;
  cmsg->cmsg_level = SOL_SOCKET;
  cmsg->cmsg_type = SCM_RIGHTS;
  cmsg->cmsg_len = CMSG_LEN(sizeof fd);
  byte_copy(CMSG_DATA(cmsg), sizeof fd, &fd);

  msg.msg_name = 0;
  msg.msg_namelen = 0;
  msg.msg_iov = 0;
  msg.msg_iovlen = 0;
  msg.msg_control = buf;
  msg.msg_controllen = cmsg->cmsg_len;

  return sendmsg(s, &msg, 0);
}

int socket_recvfd(int s) {
  struct msghdr msg;
  struct cmsghdr* cmsg;
  char buf[CMSG_SPACE(sizeof(int))];

  msg.msg_name = 0;
  msg.msg_namelen = 0;
  msg.msg_iov = 0;
  msg.msg_iovlen = 0;
  msg.msg_control = buf;
  msg.msg_controllen = sizeof buf;

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

  for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
    if(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
      return *(int *)CMSG_DATA(cmsg);

  errno = error_noent;
  return -1;
}
