8198928: (so) SocketChannel connect may deadlock if closed at around same time that connect fails

Reviewed-by: bpb, mli
This commit is contained in:
Alan Bateman 2018-03-07 07:13:55 +00:00
parent 1deb2a7bd5
commit 889a041f22
6 changed files with 258 additions and 152 deletions

View file

@ -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;