1/*++
2/* NAME
3/*	timed_connect 3
4/* SUMMARY
5/*	connect operation with timeout
6/* SYNOPSIS
7/*	#include <sys/socket.h>
8/*	#include <timed_connect.h>
9/*
10/*	int	timed_connect(fd, buf, buf_len, timeout)
11/*	int	fd;
12/*	struct sockaddr	*buf;
13/*	int	buf_len;
14/*	int	timeout;
15/* DESCRIPTION
16/*	timed_connect() implement a BSD socket connect() operation that is
17/*	bounded in time.
18/*
19/*	Arguments:
20/* .IP fd
21/*	File descriptor in the range 0..FD_SETSIZE. This descriptor
22/*	must be set to non-blocking mode prior to calling timed_connect().
23/* .IP buf
24/*	Socket address buffer pointer.
25/* .IP buf_len
26/*	Size of socket address buffer.
27/* .IP timeout
28/*	The deadline in seconds. This must be a number > 0.
29/* DIAGNOSTICS
30/*	Panic: interface violations.
31/*	When the operation does not complete within the deadline, the
32/*	result value is -1, and errno is set to ETIMEDOUT.
33/*	All other returns are identical to those of a blocking connect(2)
34/*	operation.
35/* WARNINGS
36/* .ad
37/* .fi
38/*	A common error is to call timed_connect() without enabling
39/*	non-blocking I/O on the socket. In that case, the \fItimeout\fR
40/*	parameter takes no effect.
41/* LICENSE
42/* .ad
43/* .fi
44/*	The Secure Mailer license must be distributed with this software.
45/* AUTHOR(S)
46/*	Wietse Venema
47/*	IBM T.J. Watson Research
48/*	P.O. Box 704
49/*	Yorktown Heights, NY 10598, USA
50/*--*/
51
52/* System library. */
53
54#include <sys_defs.h>
55#include <sys/socket.h>
56#include <errno.h>
57
58/* Utility library. */
59
60#include "msg.h"
61#include "iostuff.h"
62#include "sane_connect.h"
63#include "timed_connect.h"
64
65/* timed_connect - connect with deadline */
66
67int     timed_connect(int sock, struct sockaddr * sa, int len, int timeout)
68{
69    int     error;
70    SOCKOPT_SIZE error_len;
71
72    /*
73     * Sanity check. Just like with timed_wait(), the timeout must be a
74     * positive number.
75     */
76    if (timeout <= 0)
77	msg_panic("timed_connect: bad timeout: %d", timeout);
78
79    /*
80     * Start the connection, and handle all possible results.
81     */
82    if (sane_connect(sock, sa, len) == 0)
83	return (0);
84    if (errno != EINPROGRESS)
85	return (-1);
86
87    /*
88     * A connection is in progress. Wait for a limited amount of time for
89     * something to happen. If nothing happens, report an error.
90     */
91    if (write_wait(sock, timeout) < 0)
92	return (-1);
93
94    /*
95     * Something happened. Some Solaris 2 versions have getsockopt() itself
96     * return the error, instead of returning it via the parameter list.
97     */
98    error = 0;
99    error_len = sizeof(error);
100    if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &error, &error_len) < 0)
101	return (-1);
102    if (error) {
103	errno = error;
104	return (-1);
105    }
106
107    /*
108     * No problems.
109     */
110    return (0);
111}
112