xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/timed_connect.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1*e89934bbSchristos /*	$NetBSD: timed_connect.c,v 1.2 2017/02/14 01:16:49 christos Exp $	*/
241fbaed0Stron 
341fbaed0Stron /*++
441fbaed0Stron /* NAME
541fbaed0Stron /*	timed_connect 3
641fbaed0Stron /* SUMMARY
741fbaed0Stron /*	connect operation with timeout
841fbaed0Stron /* SYNOPSIS
941fbaed0Stron /*	#include <sys/socket.h>
1041fbaed0Stron /*	#include <timed_connect.h>
1141fbaed0Stron /*
1241fbaed0Stron /*	int	timed_connect(fd, buf, buf_len, timeout)
1341fbaed0Stron /*	int	fd;
1441fbaed0Stron /*	struct sockaddr	*buf;
1541fbaed0Stron /*	int	buf_len;
1641fbaed0Stron /*	int	timeout;
1741fbaed0Stron /* DESCRIPTION
1841fbaed0Stron /*	timed_connect() implement a BSD socket connect() operation that is
1941fbaed0Stron /*	bounded in time.
2041fbaed0Stron /*
2141fbaed0Stron /*	Arguments:
2241fbaed0Stron /* .IP fd
2341fbaed0Stron /*	File descriptor in the range 0..FD_SETSIZE. This descriptor
2441fbaed0Stron /*	must be set to non-blocking mode prior to calling timed_connect().
2541fbaed0Stron /* .IP buf
2641fbaed0Stron /*	Socket address buffer pointer.
2741fbaed0Stron /* .IP buf_len
2841fbaed0Stron /*	Size of socket address buffer.
2941fbaed0Stron /* .IP timeout
3041fbaed0Stron /*	The deadline in seconds. This must be a number > 0.
3141fbaed0Stron /* DIAGNOSTICS
3241fbaed0Stron /*	Panic: interface violations.
3341fbaed0Stron /*	When the operation does not complete within the deadline, the
3441fbaed0Stron /*	result value is -1, and errno is set to ETIMEDOUT.
3541fbaed0Stron /*	All other returns are identical to those of a blocking connect(2)
3641fbaed0Stron /*	operation.
3741fbaed0Stron /* WARNINGS
3841fbaed0Stron /* .ad
3941fbaed0Stron /* .fi
4041fbaed0Stron /*	A common error is to call timed_connect() without enabling
4141fbaed0Stron /*	non-blocking I/O on the socket. In that case, the \fItimeout\fR
4241fbaed0Stron /*	parameter takes no effect.
4341fbaed0Stron /* LICENSE
4441fbaed0Stron /* .ad
4541fbaed0Stron /* .fi
4641fbaed0Stron /*	The Secure Mailer license must be distributed with this software.
4741fbaed0Stron /* AUTHOR(S)
4841fbaed0Stron /*	Wietse Venema
4941fbaed0Stron /*	IBM T.J. Watson Research
5041fbaed0Stron /*	P.O. Box 704
5141fbaed0Stron /*	Yorktown Heights, NY 10598, USA
5241fbaed0Stron /*--*/
5341fbaed0Stron 
5441fbaed0Stron /* System library. */
5541fbaed0Stron 
5641fbaed0Stron #include <sys_defs.h>
5741fbaed0Stron #include <sys/socket.h>
5841fbaed0Stron #include <errno.h>
5941fbaed0Stron 
6041fbaed0Stron /* Utility library. */
6141fbaed0Stron 
6241fbaed0Stron #include "msg.h"
6341fbaed0Stron #include "iostuff.h"
6441fbaed0Stron #include "sane_connect.h"
6541fbaed0Stron #include "timed_connect.h"
6641fbaed0Stron 
6741fbaed0Stron /* timed_connect - connect with deadline */
6841fbaed0Stron 
timed_connect(int sock,struct sockaddr * sa,int len,int timeout)6941fbaed0Stron int     timed_connect(int sock, struct sockaddr *sa, int len, int timeout)
7041fbaed0Stron {
7141fbaed0Stron     int     error;
7241fbaed0Stron     SOCKOPT_SIZE error_len;
7341fbaed0Stron 
7441fbaed0Stron     /*
7541fbaed0Stron      * Sanity check. Just like with timed_wait(), the timeout must be a
7641fbaed0Stron      * positive number.
7741fbaed0Stron      */
7841fbaed0Stron     if (timeout <= 0)
7941fbaed0Stron 	msg_panic("timed_connect: bad timeout: %d", timeout);
8041fbaed0Stron 
8141fbaed0Stron     /*
8241fbaed0Stron      * Start the connection, and handle all possible results.
8341fbaed0Stron      */
8441fbaed0Stron     if (sane_connect(sock, sa, len) == 0)
8541fbaed0Stron 	return (0);
8641fbaed0Stron     if (errno != EINPROGRESS)
8741fbaed0Stron 	return (-1);
8841fbaed0Stron 
8941fbaed0Stron     /*
9041fbaed0Stron      * A connection is in progress. Wait for a limited amount of time for
9141fbaed0Stron      * something to happen. If nothing happens, report an error.
9241fbaed0Stron      */
9341fbaed0Stron     if (write_wait(sock, timeout) < 0)
9441fbaed0Stron 	return (-1);
9541fbaed0Stron 
9641fbaed0Stron     /*
9741fbaed0Stron      * Something happened. Some Solaris 2 versions have getsockopt() itself
9841fbaed0Stron      * return the error, instead of returning it via the parameter list.
9941fbaed0Stron      */
10041fbaed0Stron     error = 0;
10141fbaed0Stron     error_len = sizeof(error);
102e262b48eSchristos     if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *) &error, &error_len) < 0)
10341fbaed0Stron 	return (-1);
10441fbaed0Stron     if (error) {
10541fbaed0Stron 	errno = error;
10641fbaed0Stron 	return (-1);
10741fbaed0Stron     }
10841fbaed0Stron 
10941fbaed0Stron     /*
11041fbaed0Stron      * No problems.
11141fbaed0Stron      */
11241fbaed0Stron     return (0);
11341fbaed0Stron }
114