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 }