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