5
/* start UNIX-domain file descriptor listener
9
/* int upass_listen(path, backlog, block_mode)
14
/* int upass_accept(fd)
17
/* This module implements a listener that receives one file descriptor
18
/* across each UNIX-domain connection that is made to it.
20
/* upass_listen() creates a listener endpoint with the specified
21
/* permissions, and returns a file descriptor to be used for accepting
24
/* upass_accept() accepts a descriptor.
28
/* Null-terminated string with connection destination.
30
/* This argument exists for compatibility and is ignored.
32
/* Either NON_BLOCKING or BLOCKING. This does not affect the
33
/* mode of accepted connections.
35
/* File descriptor returned by upass_listen().
37
/* Fatal errors: upass_listen() aborts upon any system call failure.
38
/* upass_accept() leaves all error handling up to the caller.
42
/* The Secure Mailer license must be distributed with this software.
45
/* IBM T.J. Watson Research
47
/* Yorktown Heights, NY 10598, USA
53
#include <sys/socket.h>
57
/* Utility library. */
60
#include <sane_accept.h>
63
/* upass_accept - accept descriptor */
65
int upass_accept(int listen_fd)
67
const char *myname = "upass_accept";
71
accept_fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0);
74
msg_warn("%s: accept connection: %m", myname);
77
if (read_wait(accept_fd, 100) < 0)
78
msg_warn("%s: timeout receiving file descriptor: %m", myname);
79
else if ((recv_fd = unix_recv_fd(accept_fd)) < 0)
80
msg_warn("%s: cannot receive file descriptor: %m", myname);
81
if (close(accept_fd) < 0)
82
msg_warn("%s: close: %m", myname);
93
/* Utility library. */
97
#include <sane_accept.h>
102
* It would be nice if a client could make one UNIX-domain connection to a
103
* Postfix master service, send multiple descriptors, and have each
104
* descriptor handled by the first available child process.
106
* Possible solutions:
108
* - Either the master process accepts the UNIX-domain connection and forwards
109
* each descriptor sent by the client to the first available child process.
110
* That's what the code below does. Unfortunately, this approach is
111
* inconsistent with the Postfix architecture which tries to eliminate the
112
* master from connection management as much as possible.
114
* - Or one child processes accepts the UNIX-domain connection and sends a
115
* shared socketpair half to the client. The other socketpair half is shared
116
* with the master and all the child's siblings. The client then sends its
117
* descriptors over the socketpair, and each descriptor is available to any
118
* child process that is waiting for work.
120
* If the second solution did not use a shared socketpair, then all the
121
* client's descriptors would be available only to the child process that
122
* accepted the UNIX-domain connection. That results in poor performance.
124
* Unfortunately, having to receive a descriptor before being able to send one
125
* or more descriptors is ugly from the client's point of view.
128
#define upass_accept(fd) unix_recv_fd(fd)
130
/* upass_plumbing - operate the hidden descriptor passing machinery */
132
static void upass_plumbing(int unused_event, char *context)
134
const char *myname = "upass_plumbing";
135
UPASS_INFO *info = (UNIX_UPASS_INFO *) context;
139
* Each time a client connects to the hidden UNIX-domain socket, call
140
* unix_send_fd() to send one half of the hidden socketpair across a
141
* short-lived UNIX-domain connection. Wait until the client closes the
142
* UNIX-domain connection before closing the connection. This wait needs
143
* to be time limited.
145
fd = sane_accept(info->unixsock, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0);
148
msg_fatal("%s: accept connection: %m", myname);
150
if (unix_send_fd(fd, info->halfpair) < 0)
151
msg_warn("%s: cannot send file descriptor: %m", myname);
152
if (read_wait(fd, 5) < 0)
153
msg_warn("%s: read timeout", myname);
155
msg_warn("%s: close: %m", myname);
159
/* upass_listen - set up hidden descriptor passing machinery */
161
int upass_listen(const char *path, int backlog, int blocking, UPASS_INFO **ip)
167
* Create a UNIX-domain socket with unix_listen() and create a
168
* socketpair. One socketpair half is returned to the caller. The other
169
* half is part of the hidden machinery, together with the UNIX-domain
172
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0)
173
msg_fatal("socketpair: %m");
174
info = (UPASS_INFO *) mymalloc(sizeof(*info));
175
info->halfpair = pair[0];
176
info->unixsock = unix_listen(path, backlog, blocking);
177
event_request_read(info->unixsock, upass_plumbing, (char *) info);
182
/* upass_shutdown - tear down hidden descriptor passing machinery */
184
void upass_shutdown(UPASS_INFO *info)
186
event_disable_readwrite(upass_info->unixsock)
187
if (close(info->unixsock) < 0)
188
msg_warn("%s: close unixsock: %m", myname);
189
if (close(info->halfpair) < 0)
190
msg_warn("%s: close halfpair: %m", myname);
191
myfree((char *) info);