No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / unix_recv_fd.c
blobf524d2f64260d1246493f89bc0e65467e5cebc63
1 /* $NetBSD: unix_recv_fd.c,v 1.1.1.1 2009/06/23 10:09:01 tron Exp $ */
3 /*++
4 /* NAME
5 /* unix_recv_fd 3
6 /* SUMMARY
7 /* receive file descriptor
8 /* SYNOPSIS
9 /* #include <iostuff.h>
11 /* int unix_recv_fd(fd)
12 /* int fd;
13 /* DESCRIPTION
14 /* unix_recv_fd() receives a file descriptor via the specified
15 /* UNIX-domain socket. The result value is the received descriptor.
17 /* Arguments:
18 /* .IP fd
19 /* File descriptor.
20 /* DIAGNOSTICS
21 /* unix_recv_fd() returns -1 upon failure.
22 /* LICENSE
23 /* .ad
24 /* .fi
25 /* The Secure Mailer license must be distributed with this software.
26 /* AUTHOR(S)
27 /* Wietse Venema
28 /* IBM T.J. Watson Research
29 /* P.O. Box 704
30 /* Yorktown Heights, NY 10598, USA
31 /*--*/
33 /* System library. */
35 #include <sys_defs.h> /* includes <sys/types.h> */
36 #include <sys/socket.h>
37 #include <sys/uio.h>
38 #include <string.h>
40 /* Utility library. */
42 #include <msg.h>
43 #include <iostuff.h>
45 /* unix_recv_fd - receive file descriptor */
47 int unix_recv_fd(int fd)
49 const char *myname = "unix_recv_fd";
52 * This code does not work with version <2.2 Linux kernels, and it does
53 * not compile with version <2 Linux libraries.
55 #ifdef CANT_USE_SEND_RECV_MSG
56 msg_warn("%s: your system has no support for file descriptor passing",
57 myname);
58 return (-1);
59 #else
60 struct msghdr msg;
61 int newfd;
62 struct iovec iov[1];
63 char buf[1];
66 * Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1,
67 * Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE, for
68 * portability to LP64 environments.
70 #if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
71 union {
72 struct cmsghdr just_for_alignment;
73 char control[CMSG_SPACE(sizeof(newfd))];
74 } control_un;
75 struct cmsghdr *cmptr;
77 memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */
78 msg.msg_control = control_un.control;
79 msg.msg_controllen = sizeof(control_un.control); /* Fix 200506 */
80 #else
81 msg.msg_accrights = (char *) &newfd;
82 msg.msg_accrightslen = sizeof(newfd);
83 #endif
85 msg.msg_name = 0;
86 msg.msg_namelen = 0;
89 * XXX We don't want to pass any data, just a file descriptor. However,
90 * setting msg.msg_iov = 0 and msg.msg_iovlen = 0 causes trouble: we need
91 * to read_wait() before we can receive the descriptor, and the code
92 * fails after the first descriptor when we attempt to receive a sequence
93 * of descriptors.
95 iov->iov_base = buf;
96 iov->iov_len = sizeof(buf);
97 msg.msg_iov = iov;
98 msg.msg_iovlen = 1;
100 if (recvmsg(fd, &msg, 0) < 0)
101 return (-1);
103 #if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
104 if ((cmptr = CMSG_FIRSTHDR(&msg)) != 0
105 && cmptr->cmsg_len == CMSG_LEN(sizeof(newfd))) {
106 if (cmptr->cmsg_level != SOL_SOCKET)
107 msg_fatal("%s: control level %d != SOL_SOCKET",
108 myname, cmptr->cmsg_level);
109 if (cmptr->cmsg_type != SCM_RIGHTS)
110 msg_fatal("%s: control type %d != SCM_RIGHTS",
111 myname, cmptr->cmsg_type);
112 return (*(int *) CMSG_DATA(cmptr));
113 } else
114 return (-1);
115 #else
116 if (msg.msg_accrightslen == sizeof(newfd))
117 return (newfd);
118 else
119 return (-1);
120 #endif
121 #endif
124 #ifdef TEST
127 * Proof-of-concept program. Receive a descriptor (presumably from the
128 * unix_send_fd test program) and copy its content until EOF.
130 #include <unistd.h>
131 #include <string.h>
132 #include <stdlib.h>
133 #include <split_at.h>
134 #include <listen.h>
136 int main(int argc, char **argv)
138 char *transport;
139 char *endpoint;
140 int listen_sock;
141 int client_sock;
142 int client_fd;
143 ssize_t read_count;
144 char buf[1024];
146 if (argc != 2
147 || (endpoint = split_at(transport = argv[1], ':')) == 0
148 || *endpoint == 0 || *transport == 0)
149 msg_fatal("usage: %s transport:endpoint", argv[0]);
151 if (strcmp(transport, "unix") == 0) {
152 listen_sock = unix_listen(endpoint, 10, BLOCKING);
153 } else {
154 msg_fatal("invalid transport name: %s", transport);
156 if (listen_sock < 0)
157 msg_fatal("listen %s:%s: %m", transport, endpoint);
159 client_sock = accept(listen_sock, (struct sockaddr *) 0, (SOCKADDR_SIZE) 0);
160 if (client_sock < 0)
161 msg_fatal("accept: %m");
163 while ((client_fd = unix_recv_fd(client_sock)) >= 0) {
164 msg_info("client_fd = %d", client_fd);
165 while ((read_count = read(client_fd, buf, sizeof(buf))) > 0)
166 write(1, buf, read_count);
167 if (read_count < 0)
168 msg_fatal("read: %m");
169 close(client_fd);
171 exit(0);
174 #endif