fdpass: new module.
[ccan] / ccan / fdpass / fdpass.c
1 /* CC0 license (public domain) - see LICENSE file for details */
2 #include <ccan/fdpass/fdpass.h>
3 #include <sys/socket.h>
4 #include <errno.h>
5 #include <string.h>
6
7 bool fdpass_send(int sockout, int fd)
8 {
9         /* From the cmsg(3) manpage: */
10         struct msghdr msg = { 0 };
11         struct cmsghdr *cmsg;
12         struct iovec iov;
13         char c = 0;
14         union {         /* Ancillary data buffer, wrapped in a union
15                            in order to ensure it is suitably aligned */
16                 char buf[CMSG_SPACE(sizeof(fd))];
17                 struct cmsghdr align;
18         } u;
19
20         msg.msg_control = u.buf;
21         msg.msg_controllen = sizeof(u.buf);
22         memset(&u, 0, sizeof(u));
23         cmsg = CMSG_FIRSTHDR(&msg);
24         cmsg->cmsg_level = SOL_SOCKET;
25         cmsg->cmsg_type = SCM_RIGHTS;
26         cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
27         memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
28
29         msg.msg_name = NULL;
30         msg.msg_namelen = 0;
31         msg.msg_iov = &iov;
32         msg.msg_iovlen = 1;
33         msg.msg_flags = 0;
34
35         /* Keith Packard reports that 0-length sends don't work, so we
36          * always send 1 byte. */
37         iov.iov_base = &c;
38         iov.iov_len = 1;
39
40         return sendmsg(sockout, &msg, 0) == 1;
41 }
42
43 int fdpass_recv(int sockin)
44 {
45         /* From the cmsg(3) manpage: */
46         struct msghdr msg = { 0 };
47         struct cmsghdr *cmsg;
48         struct iovec iov;
49         int fd;
50         char c;
51         union {         /* Ancillary data buffer, wrapped in a union
52                            in order to ensure it is suitably aligned */
53                 char buf[CMSG_SPACE(sizeof(fd))];
54                 struct cmsghdr align;
55         } u;
56
57         msg.msg_control = u.buf;
58         msg.msg_controllen = sizeof(u.buf);
59
60         msg.msg_name = NULL;
61         msg.msg_namelen = 0;
62         msg.msg_iov = &iov;
63         msg.msg_iovlen = 1;
64         msg.msg_flags = 0;
65
66         iov.iov_base = &c;
67         iov.iov_len = 1;
68
69         if (recvmsg(sockin, &msg, 0) < 0)
70                 return -1;
71
72         cmsg = CMSG_FIRSTHDR(&msg);
73         if (!cmsg
74             || cmsg->cmsg_len != CMSG_LEN(sizeof(fd))
75             || cmsg->cmsg_level != SOL_SOCKET
76             || cmsg->cmsg_type != SCM_RIGHTS) {
77                 errno = -EINVAL;
78                 return -1;
79         }
80
81         memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
82         return fd;
83 }