Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / upass_connect.c
bloba1edec8b4f713b684b58b14601281285294d51b8
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* upass_connect 3
6 /* SUMMARY
7 /* connect to UNIX-domain file descriptor listener
8 /* SYNOPSIS
9 /* #include <connect.h>
11 /* int upass_connect(addr, block_mode, timeout)
12 /* const char *addr;
13 /* int block_mode;
14 /* int timeout;
15 /* DESCRIPTION
16 /* upass_connect() connects to a file descriptor listener in
17 /* the UNIX domain at the specified address, sends one half
18 /* of a socketpair to the listener, and returns the other half
19 /* to the caller.
21 /* The file descriptor transporting connection is closed by
22 /* a background thread. Some kernels might otherwise discard
23 /* the descriptor before the server has received it.
25 /* Arguments:
26 /* .IP addr
27 /* Null-terminated string with connection destination.
28 /* .IP block_mode
29 /* Either NON_BLOCKING for a non-blocking socket, or BLOCKING for
30 /* blocking mode. This setting has no effect on the connection
31 /* establishment process.
32 /* .IP timeout
33 /* Bounds the number of seconds that the operation may take. Specify
34 /* a value <= 0 to disable the time limit.
35 /* DIAGNOSTICS
36 /* The result is -1 in case the connection could not be made.
37 /* Fatal errors: other system call failures.
38 /* LICENSE
39 /* .ad
40 /* .fi
41 /* The Secure Mailer license must be distributed with this software.
42 /* AUTHOR(S)
43 /* Wietse Venema
44 /* IBM T.J. Watson Research
45 /* P.O. Box 704
46 /* Yorktown Heights, NY 10598, USA
47 /*--*/
49 /* System interfaces. */
51 #include <sys_defs.h>
52 #include <sys/socket.h>
53 #include <sys/un.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <errno.h>
58 /* Utility library. */
60 #include <msg.h>
61 #include <iostuff.h>
62 #include <sane_connect.h>
63 #include <connect.h>
64 #include <timed_connect.h>
65 #include <events.h>
66 #include <mymalloc.h>
67 #include <sane_socketpair.h>
70 * Workaround for hostile kernels that don't support graceful shutdown.
72 struct upass_connect {
73 int fd;
74 char *service;
77 /* upass_connect_event - disconnect from peer */
79 static void upass_connect_event(int event, char *context)
81 struct upass_connect *up = (struct upass_connect *) context;
82 static const char *myname = "upass_connect_event";
85 * Disconnect.
87 if (event == EVENT_TIME)
88 msg_warn("%s: read timeout for service %s", myname, up->service);
89 event_disable_readwrite(up->fd);
90 event_cancel_timer(upass_connect_event, context);
91 if (close(up->fd) < 0)
92 msg_warn("%s: close %s: %m", myname, up->service);
93 myfree(up->service);
94 myfree((char *) up);
97 /* upass_connect - connect to UNIX-domain file descriptor listener */
99 int upass_connect(const char *addr, int block_mode, int timeout)
101 struct upass_connect *up;
102 int pair[2];
103 int sock;
106 * Connect.
108 if ((sock = unix_connect(addr, BLOCKING, timeout)) < 0)
109 return (-1);
112 * Send one socket pair half to the server.
114 #define OUR_HALF 0
115 #define THEIR_HALF 1
117 if (sane_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) {
118 close(sock);
119 return (-1);
121 if (unix_send_fd(sock, pair[THEIR_HALF]) < 0) {
122 close(pair[THEIR_HALF]);
123 close(pair[OUR_HALF]);
124 close(sock);
125 return (-1);
127 close(pair[THEIR_HALF]);
130 * Return the other socket pair half to the caller. Don't close the
131 * control socket just yet, but wait until the receiver closes it first.
132 * Otherwise, some hostile kernel might discard the socket that we just
133 * sent.
135 up = (struct upass_connect *) mymalloc(sizeof(*up));
136 up->fd = sock;
137 up->service = mystrdup(addr);
138 if (timeout > 0)
139 event_request_timer(upass_connect_event, (char *) up, timeout + 100);
140 event_enable_read(sock, upass_connect_event, (char *) up);
141 non_blocking(pair[OUR_HALF], block_mode);
142 return (pair[OUR_HALF]);