skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

ancil_recv_fd.c (1544B)


      1 /* ISC license. */
      2 
      3 #include <skalibs/sysdeps.h>
      4 #include <skalibs/nonposix.h>
      5 
      6 #include <errno.h>
      7 #include <string.h>
      8 #include <sys/uio.h>
      9 #include <sys/socket.h>
     10 
     11 #include <skalibs/allreadwrite.h>
     12 #include <skalibs/djbunix.h>
     13 #include <skalibs/ancil.h>
     14 #include <skalibs/posixishard.h>
     15 
     16 union aligner_u
     17 {
     18   struct cmsghdr cmsghdr ;
     19   int i ;
     20 } ;
     21 
     22 int ancil_recv_fd (int sock, char expected_ch)
     23 {
     24   static int const awesomeflags =
     25 #ifdef SKALIBS_HASMSGDONTWAIT
     26     MSG_DONTWAIT
     27 #else
     28     0
     29 #endif
     30     |
     31 #ifdef SKALIBS_HASCMSGCLOEXEC
     32     MSG_CMSG_CLOEXEC
     33 #else
     34     0
     35 #endif
     36     ;
     37   int fd ;
     38   struct cmsghdr *c ;
     39   ssize_t r ;
     40   char ch ;
     41   struct iovec v = { .iov_base = &ch, .iov_len = 1 } ;
     42   union aligner_u ancilbuf[1 + (CMSG_SPACE(sizeof(int)) - 1) / sizeof(union aligner_u)] ;
     43   struct msghdr msghdr =
     44   {
     45     .msg_name = 0,
     46     .msg_namelen = 0,
     47     .msg_iov = &v,
     48     .msg_iovlen = 1,
     49     .msg_flags = 0,
     50     .msg_control = ancilbuf,
     51     .msg_controllen = CMSG_SPACE(sizeof(int))
     52   } ;
     53   do r = recvmsg(sock, &msghdr, awesomeflags) ;
     54   while (r < 0 && errno == EINTR) ;
     55   if (r < 0) return r ;
     56   if (!r) return (errno = EPIPE, -1) ;
     57   c = CMSG_FIRSTHDR(&msghdr) ;
     58   if (ch != expected_ch
     59    || !c
     60    || c->cmsg_level != SOL_SOCKET
     61    || c->cmsg_type != SCM_RIGHTS
     62    || (size_t)(c->cmsg_len - (CMSG_DATA(c) - (unsigned char *)c)) != sizeof(int)) return (errno = EPROTO, -1) ;
     63   memcpy(&fd, CMSG_DATA(c), sizeof(int)) ;
     64 #ifndef SKALIBS_HASCMSGCLOEXEC
     65   if (coe(fd) < 0)
     66   {
     67     fd_close(fd) ;
     68     return -1 ;
     69   }
     70 #endif
     71   return fd ;
     72 }