mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 11:34:38 +02:00
8198928: (so) SocketChannel connect may deadlock if closed at around same time that connect fails
Reviewed-by: bpb, mli
This commit is contained in:
parent
1deb2a7bd5
commit
889a041f22
6 changed files with 258 additions and 152 deletions
|
@ -58,9 +58,7 @@ Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv *env, jobject this,
|
|||
jobject fdo, jboolean block)
|
||||
{
|
||||
int optError = 0;
|
||||
int lastError = 0;
|
||||
int result = 0;
|
||||
int retry = 0;
|
||||
int result;
|
||||
int n = sizeof(int);
|
||||
jint fd = fdval(env, fdo);
|
||||
fd_set wr, ex;
|
||||
|
@ -73,64 +71,33 @@ Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv *env, jobject this,
|
|||
|
||||
result = select(fd+1, 0, &wr, &ex, block ? NULL : &t);
|
||||
|
||||
/* save last winsock error */
|
||||
if (result == SOCKET_ERROR) {
|
||||
lastError = WSAGetLastError();
|
||||
}
|
||||
|
||||
if (block) { /* must configure socket back to blocking state */
|
||||
u_long argp = 0;
|
||||
int r = ioctlsocket(fd, FIONBIO, &argp);
|
||||
if (r == SOCKET_ERROR) {
|
||||
handleSocketError(env, WSAGetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
if (result == 0) { /* timeout */
|
||||
return block ? 0 : IOS_UNAVAILABLE;
|
||||
} else {
|
||||
if (result == SOCKET_ERROR) { /* select failed */
|
||||
handleSocketError(env, lastError);
|
||||
if (result == SOCKET_ERROR) { /* select failed */
|
||||
handleSocketError(env, WSAGetLastError());
|
||||
return IOS_THROWN;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Socket is writable or error occurred. On some Windows editions
|
||||
* the socket will appear writable when the connect fails so we
|
||||
* check for error rather than writable.
|
||||
*/
|
||||
if (!FD_ISSET(fd, &ex)) {
|
||||
return 1; /* connection established */
|
||||
// connection established if writable and no error to check
|
||||
if (FD_ISSET(fd, &wr) && !FD_ISSET(fd, &ex)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* A getsockopt( SO_ERROR ) may indicate success on NT4 even
|
||||
* though the connection has failed. The workaround is to allow
|
||||
* winsock to be scheduled and this is done via by yielding.
|
||||
* As the yield approach is problematic in heavy load situations
|
||||
* we attempt up to 3 times to get the failure reason.
|
||||
*/
|
||||
for (retry=0; retry<3; retry++) {
|
||||
result = getsockopt((SOCKET)fd,
|
||||
SOL_SOCKET,
|
||||
SO_ERROR,
|
||||
(char *)&optError,
|
||||
&n);
|
||||
if (result == SOCKET_ERROR) {
|
||||
int lastError = WSAGetLastError();
|
||||
if (lastError == WSAEINPROGRESS) {
|
||||
return IOS_UNAVAILABLE;
|
||||
}
|
||||
NET_ThrowNew(env, lastError, "getsockopt");
|
||||
return IOS_THROWN;
|
||||
result = getsockopt((SOCKET)fd,
|
||||
SOL_SOCKET,
|
||||
SO_ERROR,
|
||||
(char *)&optError,
|
||||
&n);
|
||||
if (result == SOCKET_ERROR) {
|
||||
int lastError = WSAGetLastError();
|
||||
if (lastError == WSAEINPROGRESS) {
|
||||
return IOS_UNAVAILABLE;
|
||||
}
|
||||
if (optError) {
|
||||
break;
|
||||
}
|
||||
Sleep(0);
|
||||
NET_ThrowNew(env, lastError, "getsockopt");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
|
||||
if (optError != NO_ERROR) {
|
||||
handleSocketError(env, optError);
|
||||
return IOS_THROWN;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue