mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 17:44:45 +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<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 */
|