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