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
69int     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