mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 02:13:29 +00:00
197 lines
4.2 KiB
C
197 lines
4.2 KiB
C
#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));
|
||
if (result == 0)
|
||
return 0; /* Already?!? */
|
||
|
||
if ((result < 0)
|
||
#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) {
|
||
/* timeout */
|
||
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<61>
|
||
* 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 */
|