7 /* connect to UNIX-domain file descriptor listener
9 /* #include <connect.h>
11 /* int upass_connect(addr, block_mode, timeout)
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
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.
27 /* Null-terminated string with connection destination.
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.
33 /* Bounds the number of seconds that the operation may take. Specify
34 /* a value <= 0 to disable the time limit.
36 /* The result is -1 in case the connection could not be made.
37 /* Fatal errors: other system call failures.
41 /* The Secure Mailer license must be distributed with this software.
44 /* IBM T.J. Watson Research
46 /* Yorktown Heights, NY 10598, USA
49 /* System interfaces. */
52 #include <sys/socket.h>
58 /* Utility library. */
62 #include <sane_connect.h>
64 #include <timed_connect.h>
67 #include <sane_socketpair.h>
70 * Workaround for hostile kernels that don't support graceful shutdown.
72 struct upass_connect
{
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";
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
);
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
;
108 if ((sock
= unix_connect(addr
, BLOCKING
, timeout
)) < 0)
112 * Send one socket pair half to the server.
117 if (sane_socketpair(AF_UNIX
, SOCK_STREAM
, 0, pair
) < 0) {
121 if (unix_send_fd(sock
, pair
[THEIR_HALF
]) < 0) {
122 close(pair
[THEIR_HALF
]);
123 close(pair
[OUR_HALF
]);
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
135 up
= (struct upass_connect
*) mymalloc(sizeof(*up
));
137 up
->service
= mystrdup(addr
);
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
]);