version 2.39.2.2, 1995/05/16 20:11:50
|
version 2.39.2.3, 1995/05/17 19:16:43
|
Line 1038 PUBLIC int HTDoConnect ARGS5(HTNetInfo *
|
Line 1038 PUBLIC int HTDoConnect ARGS5(HTNetInfo *
|
/* If we are trying to connect to a multi-homed host then loop here until |
/* If we are trying to connect to a multi-homed host then loop here until |
success or we have tried all IP-addresses */ |
success or we have tried all IP-addresses */ |
do { |
do { |
if (net->sockfd==INVSOC) { |
if (net->sockfd==INVSOC) { |
int hosts; |
int hosts; |
if ((hosts = HTParseInet(&net->sock_addr, host, use_cur)) < 0) { |
if ((hosts = HTParseInet(&net->sock_addr, host, use_cur)) < 0) { |
if (PROT_TRACE) |
if (PROT_TRACE) |
fprintf(TDEST, "HTDoConnect. Can't locate remote host `%s\'\n", host); |
fprintf(TDEST, "HTDoConnect. Can't locate remote host `%s\'\n", host); |
HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST, |
HTErrorAdd(net->request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST, |
(void *) host, strlen(host), "HTDoConnect"); |
(void *) host, strlen(host), "HTDoConnect"); |
break; |
break; |
} |
} |
if (!net->addressCount && hosts > 1) |
if (!net->addressCount && hosts > 1) |
net->addressCount = hosts; |
net->addressCount = hosts; |
#ifdef DECNET |
#ifdef DECNET |
if ((net->sockfd=socket(AF_DECnet, SOCK_STREAM, 0))==INVSOC) |
if ((net->sockfd=socket(AF_DECnet, SOCK_STREAM, 0))==INVSOC) |
#else |
#else |
if ((net->sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVSOC) |
if ((net->sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVSOC) |
#endif |
#endif |
{ |
{ |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, "socket"); |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, "socket"); |
break; |
break; |
} |
} |
if (addr) |
if (addr) |
*addr = ntohl(net->sock_addr.sin_addr.s_addr); |
*addr = ntohl(net->sock_addr.sin_addr.s_addr); |
if (PROT_TRACE) |
if (PROT_TRACE) |
fprintf(TDEST, "HTDoConnect. Created socket number %d\n", |
fprintf(TDEST, "HTDoConnect. Created socket number %d\n", |
net->sockfd); |
net->sockfd); |
|
|
/* If non-blocking protocol then change socket status |
/* If non-blocking protocol then change socket status |
** I use FCNTL so that I can ask the status before I set it. |
** I use FCNTL so that I can ask the status before I set it. |
** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364) |
** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364) |
** Be CAREFULL with the old `O_NDELAY' - it will not work as read() |
** Be CAREFULL with the old `O_NDELAY' - it will not work as read() |
** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and |
** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and |
** does NOT work on SVR4 systems. O_NONBLOCK is POSIX. |
** does NOT work on SVR4 systems. O_NONBLOCK is POSIX. |
*/ |
*/ |
if (!HTProtocolBlocking(net->request)) { |
if (!HTProtocolBlocking(net->request)) { |
#ifdef _WINDOWS |
#ifdef _WINDOWS |
{ /* begin windows scope */ |
{ /* begin windows scope */ |
HTRequest * rq = net->request; |
HTRequest * rq = net->request; |
long levents = FD_READ | FD_WRITE | FD_ACCEPT | |
long levents = FD_READ | FD_WRITE | FD_ACCEPT | |
FD_CONNECT | FD_CLOSE ; |
FD_CONNECT | FD_CLOSE ; |
int rv = 0 ; |
int rv = 0 ; |
|
|
#ifndef _WIN32 |
#ifndef _WIN32 |
if (net->request->hwnd == 0) { |
if (net->request->hwnd == 0) { |
|
|
} |
} |
#endif |
#endif |
/* N.B WSAAsyncSelect() turns on non-blocking I/O */ |
/* N.B WSAAsyncSelect() turns on non-blocking I/O */ |
|
|
if (net->request->hwnd != 0) { |
if (net->request->hwnd != 0) { |
rv = WSAAsyncSelect( net->sockfd, rq->hwnd, |
rv = WSAAsyncSelect( net->sockfd, rq->hwnd, |
rq->winMsg, levents); |
rq->winMsg, levents); |
if (rv == SOCKET_ERROR) { |
if (rv == SOCKET_ERROR) { |
status = -1 ; |
status = -1 ; |
if (PROT_TRACE) |
if (PROT_TRACE) |
fprintf(TDEST, |
fprintf(TDEST, |
"HTDoConnect: WSAAsyncSelect() fails: %d\n", |
"HTDoConnect: WSAAsyncSelect() fails: %d\n", |
WSAGetLastError()); |
WSAGetLastError()); |
} /* error returns */ |
} /* error returns */ |
} |
} else { |
else { |
int enable = 1 ; |
int enable = 1 ; |
status = IOCTL(net->sockfd, FIONBIO, &enable); |
status = IOCTL(net->sockfd, FIONBIO, &enable); |
} |
} |
} /* end scope */ |
} /* end scope */ |
|
#else |
#else |
#if defined(VMS) |
#if defined(VMS) |
{ |
{ |
int enable = 1; |
int enable = 1; |
status = IOCTL(net->sockfd, FIONBIO, &enable); |
status = IOCTL(net->sockfd, FIONBIO, &enable); |
} |
} |
#else |
#else |
if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) { |
if((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) { |
status |= O_NONBLOCK; /* POSIX */ |
status |= O_NONBLOCK; /* POSIX */ |
status = FCNTL(net->sockfd, F_SETFL, status); |
status = FCNTL(net->sockfd, F_SETFL, status); |
} |
} |
#endif /* VMS */ |
#endif /* VMS */ |
#endif /* WINDOW */ |
#endif /* WINDOW */ |
if (status == -1) { |
if (status == -1) { |
if (PROT_TRACE) |
if (PROT_TRACE) |
fprintf(TDEST, "HTDoConnect. Can NOT make socket non-blocking\n"); |
fprintf(TDEST, "HTDoConnect. Can NOT make socket non-blocking\n"); |
} else if (PROT_TRACE) |
} else if (PROT_TRACE) |
fprintf(TDEST, "HTDoConnect. Using NON_BLOCKING I/O\n"); |
fprintf(TDEST, "HTDoConnect. Using NON_BLOCKING I/O\n"); |
} |
} |
|
|
/* If multi-homed host then start timer on connection */ |
/* If multi-homed host then start timer on connection */ |
if (net->addressCount >= 1) |
if (net->addressCount >= 1) |
net->connecttime = time(NULL); |
net->connecttime = time(NULL); |
} /* IF socket is invalid */ |
} /* IF socket is invalid */ |
|
|
/* Check for interrupt */ |
/* Check for interrupt */ |
|
if (HTThreadIntr(net->sockfd)) { |
if (HTThreadIntr(net->sockfd)) { /* connect call was interrupted */ |
if (NETCLOSE(net->sockfd) < 0) |
if (NETCLOSE(net->sockfd) < 0) |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno,NO,"NETCLOSE"); |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno,NO,"NETCLOSE"); |
HTThreadState(net->sockfd, THD_CLOSE); |
HTThreadState(net->sockfd, THD_CLOSE); |
net->sockfd = INVSOC; |
net->sockfd = INVSOC; |
free(p1); |
free(p1); |
return HT_INTERRUPTED; |
return HT_INTERRUPTED; |
} |
} |
|
|
/* Do a connect */ |
/* Do a connect */ |
status = connect(net->sockfd, (struct sockaddr *) &net->sock_addr, |
|
sizeof(net->sock_addr)); |
status = connect(net->sockfd, (struct sockaddr *) &net->sock_addr, |
/* |
sizeof(net->sock_addr)); |
* According to the Sun man page for connect: |
/* |
* EINPROGRESS The socket is non-blocking and the con- |
* According to the Sun man page for connect: |
* nection cannot be completed immediately. |
* EINPROGRESS The socket is non-blocking and the con- |
* It is possible to select(2) for comple- |
* nection cannot be completed immediately. |
* tion by selecting the socket for writ- |
* It is possible to select(2) for comple- |
* ing. |
* tion by selecting the socket for writ- |
* According to the Motorola SVR4 man page for connect: |
* ing. |
* EAGAIN The socket is non-blocking and the con- |
* According to the Motorola SVR4 man page for connect: |
* nection cannot be completed immediately. |
* EAGAIN The socket is non-blocking and the con- |
* It is possible to select for completion |
* nection cannot be completed immediately. |
* by selecting the socket for writing. |
* It is possible to select for completion |
* However, this is only possible if the |
* by selecting the socket for writing. |
* socket STREAMS module is the topmost |
* However, this is only possible if the |
* module on the protocol stack with a |
* socket STREAMS module is the topmost |
* write service procedure. This will be |
* module on the protocol stack with a |
* the normal case. |
* write service procedure. This will be |
*/ |
* the normal case. |
|
*/ |
|
|
|
#ifdef EAGAIN |
#ifdef EAGAIN |
if ((status < 0) && ((socerrno==EINPROGRESS) || (socerrno==EAGAIN))) |
if ((status < 0) && ((socerrno==EINPROGRESS) || (socerrno==EAGAIN))) |
#else |
#else |
#ifdef WSAEWOULDBLOCK /* WinSock API */ |
#ifdef WSAEWOULDBLOCK /* WinSock API */ |
if ((status == SOCKET_ERROR) && (socerrno == WSAEWOULDBLOCK)) |
if ((status == SOCKET_ERROR) && (socerrno == WSAEWOULDBLOCK)) |
#else |
#else |
if ((status < 0) && (socerrno == EINPROGRESS)) |
if ((status < 0) && (socerrno == EINPROGRESS)) |
#endif /* WSAEWOULDBLOCK */ |
#endif /* WSAEWOULDBLOCK */ |
#endif /* EAGAIN */ |
#endif /* EAGAIN */ |
{ |
{ |
if (PROT_TRACE) |
if (PROT_TRACE) |
fprintf(TDEST, "HTDoConnect. WOULD BLOCK `%s'\n", host); |
fprintf(TDEST, "HTDoConnect. WOULD BLOCK `%s'\n", host); |
HTThreadState(net->sockfd, THD_SET_WRITE); |
HTThreadState(net->sockfd, THD_SET_WRITE); |
|
free(p1); |
|
return HT_WOULD_BLOCK; |
|
} |
|
|
|
/* We have 4 situations: single OK, Pb and multi OK, pb */ |
|
if (net->addressCount >= 1) { |
|
net->connecttime = time((long *)0) - net->connecttime; |
|
if (status < 0) { /* multi PB */ |
|
if (socerrno == EISCONN) { /* connect multi after would block*/ |
|
HTThreadState(net->sockfd, THD_CLR_WRITE); |
|
HTTCPAddrWeights(host, net->connecttime); |
free(p1); |
free(p1); |
return HT_WOULD_BLOCK; |
net->addressCount = 0; |
|
if (PROT_TRACE) |
|
fprintf(TDEST, "HTDoConnect: Socket %ld already connected\n", net->sockfd) ; |
|
return 0; |
} |
} |
|
|
if (net->addressCount >= 1) { |
HTErrorSysAdd(net->request, ERR_NON_FATAL, socerrno, NO, |
net->connecttime = time((long *)0) - net->connecttime; |
"connect"); |
if (status < 0) { |
|
if (socerrno == EISCONN) { /* connect multi after would block */ |
/* I have added EINVAL `invalid argument' as this is what I |
HTThreadState(net->sockfd, THD_CLR_WRITE); |
get back from a non-blocking connect where I should |
HTTCPAddrWeights(host, net->connecttime); |
get `connection refused' on SVR4 */ |
free(p1); |
|
net->addressCount = 0; |
|
if (PROT_TRACE) |
|
fprintf(TDEST, "HTDoConnect: Socket %ld already connected\n", net->sockfd) ; |
|
return 0; |
|
} |
|
|
|
HTErrorSysAdd(net->request, ERR_NON_FATAL, socerrno, NO, |
|
"connect"); |
|
|
|
/* I have added EINVAL `invalid argument' as this is what I |
|
get back from a non-blocking connect where I should |
|
get `connection refused' on SVR4 */ |
|
|
|
if (socerrno==ECONNREFUSED || socerrno==ETIMEDOUT || |
if (socerrno==ECONNREFUSED || socerrno==ETIMEDOUT || |
socerrno==ENETUNREACH || socerrno==EHOSTUNREACH || |
socerrno==ENETUNREACH || socerrno==EHOSTUNREACH || |
#ifdef __srv4__ |
#ifdef __srv4__ |
socerrno==EHOSTDOWN || socerrno==EINVAL) |
socerrno==EHOSTDOWN || socerrno==EINVAL) |
#else |
#else |
socerrno==EHOSTDOWN) |
socerrno==EHOSTDOWN) |
#endif |
#endif |
net->connecttime += TCP_DELAY; |
net->connecttime += TCP_DELAY; |
else |
else |
net->connecttime += TCP_PENALTY; |
net->connecttime += TCP_PENALTY; |
|
|
if (NETCLOSE(net->sockfd) < 0) |
if (NETCLOSE(net->sockfd) < 0) |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, |
"NETCLOSE"); |
"NETCLOSE"); |
HTThreadState(net->sockfd, THD_CLOSE); |
HTThreadState(net->sockfd, THD_CLOSE); |
net->sockfd = INVSOC; |
net->sockfd = INVSOC; |
HTTCPAddrWeights(host, net->connecttime); |
HTTCPAddrWeights(host, net->connecttime); |
} else { /* Connect on multi-homed */ |
} else { /* multi OK */ |
HTTCPAddrWeights(host, net->connecttime); |
HTTCPAddrWeights(host, net->connecttime); |
free(p1); |
free(p1); |
net->addressCount = 0; |
net->addressCount = 0; |
return 0; |
return 0; |
} |
} |
} else if (status < 0) { |
} else if (status < 0) { /* single PB */ |
if (socerrno==EISCONN) { /* Connect single after would block */ |
if (socerrno==EISCONN) { /* Connect single after would block */ |
HTThreadState(net->sockfd, THD_CLR_WRITE); |
HTThreadState(net->sockfd, THD_CLR_WRITE); |
net->addressCount = 0; |
net->addressCount = 0; |
free(p1); |
free(p1); |
return 0; |
return 0; |
} else { |
} else { |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, |
"connect"); |
"connect"); |
HTTCPCacheRemoveHost(host); |
HTTCPCacheRemoveHost(host); |
if (NETCLOSE(net->sockfd) < 0) |
if (NETCLOSE(net->sockfd) < 0) |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, |
HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO, |
"NETCLOSE"); |
"NETCLOSE"); |
HTThreadState(net->sockfd, THD_CLOSE); |
HTThreadState(net->sockfd, THD_CLOSE); |
break; |
break; |
} |
} |
} else { /* Connect on single homed */ |
} else { /* single OK */ |
free(p1); |
free(p1); |
net->addressCount = 0; |
net->addressCount = 0; |
return 0; |
return 0; |
} |
} |
} while (--net->addressCount); |
} while (--net->addressCount); /* End of mega loop */ |
|
|
if (PROT_TRACE) |
if (PROT_TRACE) |
fprintf(TDEST, "HTDoConnect. Connect failed\n"); |
fprintf(TDEST, "HTDoConnect. Connect failed\n"); |
free (p1); |
free (p1); |
net->addressCount = 0; |
net->addressCount = 0; |
net->sockfd = INVSOC; |
net->sockfd = INVSOC; |