2001-12-30 06:31:25 +00:00
|
|
|
|
#include "syshdrs.h"
|
|
|
|
|
|
|
|
|
|
#ifndef NO_SIGNALS
|
|
|
|
|
extern volatile Sjmp_buf gNetTimeoutJmp;
|
|
|
|
|
extern volatile Sjmp_buf gPipeJmp;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
SConnect(int sfd, const struct sockaddr_in *const addr, int tlen)
|
|
|
|
|
{
|
|
|
|
|
#ifndef NO_SIGNALS
|
|
|
|
|
int result;
|
|
|
|
|
vsio_sigproc_t sigalrm;
|
|
|
|
|
|
|
|
|
|
if (SSetjmp(gNetTimeoutJmp) != 0) {
|
|
|
|
|
alarm(0);
|
|
|
|
|
(void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
|
|
|
|
|
errno = ETIMEDOUT;
|
|
|
|
|
return (kTimeoutErr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sigalrm = (vsio_sigproc_t) SSignal(SIGALRM, SIOHandler);
|
|
|
|
|
alarm((unsigned int) tlen);
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
do {
|
|
|
|
|
result = connect(sfd, (struct sockaddr *) addr,
|
|
|
|
|
(int) sizeof(struct sockaddr_in));
|
|
|
|
|
} while ((result < 0) && (errno == EINTR));
|
|
|
|
|
|
|
|
|
|
alarm(0);
|
|
|
|
|
(void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
|
|
|
|
|
return (result);
|
|
|
|
|
#else /* NO_SIGNALS */
|
|
|
|
|
unsigned long opt;
|
|
|
|
|
fd_set ss, xx;
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
int result;
|
|
|
|
|
int cErrno;
|
|
|
|
|
#if defined(WIN32) || defined(_WINDOWS)
|
|
|
|
|
int wsaErrno;
|
|
|
|
|
int soerr, soerrsize;
|
|
|
|
|
#else
|
|
|
|
|
int optval;
|
|
|
|
|
int optlen;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
if (tlen <= 0) {
|
|
|
|
|
do {
|
|
|
|
|
result = connect(sfd, (struct sockaddr *) addr,
|
|
|
|
|
(int) sizeof(struct sockaddr_in));
|
|
|
|
|
SETERRNO
|
|
|
|
|
} while ((result < 0) && (errno == EINTR));
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef FIONBIO
|
|
|
|
|
opt = 1;
|
|
|
|
|
if (ioctlsocket(sfd, FIONBIO, &opt) != 0) {
|
|
|
|
|
SETERRNO
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (fcntl(sfd, F_GETFL, &opt) < 0) {
|
|
|
|
|
SETERRNO
|
|
|
|
|
return (-1);
|
|
|
|
|
} else if (fcntl(sfd, F_SETFL, opt | O_NONBLOCK) < 0) {
|
|
|
|
|
SETERRNO
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
result = connect(sfd, (struct sockaddr *) addr,
|
|
|
|
|
(int) sizeof(struct sockaddr_in));
|
2005-05-07 21:24:31 +00:00
|
|
|
|
if (result == 0)
|
2001-12-30 06:31:25 +00:00
|
|
|
|
return 0; /* Already?!? */
|
|
|
|
|
|
2005-05-07 21:24:31 +00:00
|
|
|
|
if ((result < 0)
|
2001-12-30 06:31:25 +00:00
|
|
|
|
#if defined(WIN32) || defined(_WINDOWS)
|
|
|
|
|
&& ((wsaErrno = WSAGetLastError()) != WSAEWOULDBLOCK)
|
|
|
|
|
&& (wsaErrno != WSAEINPROGRESS)
|
|
|
|
|
#else
|
|
|
|
|
&& (errno != EWOULDBLOCK) && (errno != EINPROGRESS)
|
|
|
|
|
#endif
|
|
|
|
|
) {
|
|
|
|
|
SETERRNO
|
|
|
|
|
shutdown(sfd, 2);
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
cErrno = errno;
|
|
|
|
|
|
|
|
|
|
forever {
|
|
|
|
|
#if defined(WIN32) || defined(_WINDOWS)
|
|
|
|
|
WSASetLastError(0);
|
|
|
|
|
#endif
|
|
|
|
|
FD_ZERO(&ss);
|
|
|
|
|
FD_SET(sfd, &ss);
|
|
|
|
|
xx = ss;
|
|
|
|
|
tv.tv_sec = tlen;
|
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
|
result = select(sfd + 1, NULL, SELECT_TYPE_ARG234 &ss, SELECT_TYPE_ARG234 &xx, SELECT_TYPE_ARG5 &tv);
|
|
|
|
|
if (result == 1) {
|
|
|
|
|
/* ready */
|
|
|
|
|
break;
|
|
|
|
|
} else if (result == 0) {
|
2005-05-07 21:24:31 +00:00
|
|
|
|
/* timeout */
|
2001-12-30 06:31:25 +00:00
|
|
|
|
errno = ETIMEDOUT;
|
|
|
|
|
SETWSATIMEOUTERR
|
|
|
|
|
/* Don't bother turning off FIONBIO */
|
|
|
|
|
return (kTimeoutErr);
|
|
|
|
|
} else if (errno != EINTR) {
|
|
|
|
|
/* Don't bother turning off FIONBIO */
|
|
|
|
|
SETERRNO
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Supposedly once the select() returns with a writable
|
|
|
|
|
* descriptor, it is connected and we don't need to
|
|
|
|
|
* recall connect(). When select() returns an exception,
|
|
|
|
|
* the connection failed -- we can get the connect error
|
|
|
|
|
* doing a write on the socket which will err out.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (FD_ISSET(sfd, &xx)) {
|
|
|
|
|
#if defined(WIN32) || defined(_WINDOWS)
|
|
|
|
|
errno = 0;
|
|
|
|
|
soerr = 0;
|
|
|
|
|
soerrsize = sizeof(soerr);
|
|
|
|
|
result = getsockopt(sfd, SOL_SOCKET, SO_ERROR, (char *) &soerr, &soerrsize);
|
|
|
|
|
if ((result >= 0) && (soerr != 0)) {
|
|
|
|
|
errno = soerr;
|
|
|
|
|
} else {
|
|
|
|
|
errno = 0;
|
|
|
|
|
(void) send(sfd, "\0", 1, 0);
|
|
|
|
|
SETERRNO
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
errno = 0;
|
|
|
|
|
(void) send(sfd, "\0", 1, 0);
|
|
|
|
|
#endif
|
|
|
|
|
result = errno;
|
|
|
|
|
shutdown(sfd, 2);
|
|
|
|
|
errno = result;
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(WIN32) || defined(_WINDOWS)
|
|
|
|
|
#else
|
|
|
|
|
if (cErrno == EINPROGRESS) {
|
|
|
|
|
/*
|
|
|
|
|
* [from Linux connect(2) page]
|
|
|
|
|
*
|
|
|
|
|
* EINPROGRESS
|
|
|
|
|
*
|
|
|
|
|
* The socket is non-blocking and the connection can<EFBFBD>
|
|
|
|
|
* not be completed immediately. It is possible to
|
|
|
|
|
* select(2) or poll(2) for completion by selecting
|
|
|
|
|
* the socket for writing. After select indicates
|
|
|
|
|
* writability, use getsockopt(2) to read the
|
|
|
|
|
* SO_ERROR option at level SOL_SOCKET to determine
|
|
|
|
|
* whether connect completed successfully (SO_ERROR
|
|
|
|
|
* is zero) or unsuccessfully (SO_ERROR is one of the
|
|
|
|
|
* usual error codes listed above, explaining the
|
|
|
|
|
* reason for the failure).
|
|
|
|
|
*/
|
|
|
|
|
optval = 0;
|
|
|
|
|
optlen = sizeof(optval);
|
|
|
|
|
if (getsockopt(sfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == 0) {
|
|
|
|
|
errno = optval;
|
|
|
|
|
if (errno != 0)
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef FIONBIO
|
|
|
|
|
opt = 0;
|
|
|
|
|
if (ioctlsocket(sfd, FIONBIO, &opt) != 0) {
|
|
|
|
|
SETERRNO
|
|
|
|
|
shutdown(sfd, 2);
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (fcntl(sfd, F_SETFL, opt) < 0) {
|
|
|
|
|
SETERRNO
|
|
|
|
|
shutdown(sfd, 2);
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
#endif /* NO_SIGNALS */
|
|
|
|
|
} /* SConnect */
|