register socket with exceptfds when calling select on Windows

This allows us to get connection errors like WSAECONNREFUSED in
non-blocking mode.
This commit is contained in:
Joel Dice 2010-02-19 16:41:27 -07:00
parent 48cc14f8ed
commit fdf9c5087b

View File

@ -77,6 +77,19 @@ errorString(JNIEnv* e, int n)
#endif #endif
} }
inline jbyteArray
socketErrorString(JNIEnv* e, int n)
{
#ifdef PLATFORM_WINDOWS
const unsigned size = 64;
char buffer[size];
snprintf(buffer, size, "wsa code: %d", n);
return charsToArray(e, buffer);
#else
return errorString(e, n);
#endif
}
inline jbyteArray inline jbyteArray
errorString(JNIEnv* e) errorString(JNIEnv* e)
{ {
@ -243,6 +256,24 @@ doListen(JNIEnv* e, int s, sockaddr_in* address)
} }
} }
bool
doFinishConnect(JNIEnv* e, int socket)
{
int error;
socklen_t size = sizeof(int);
int r = getsockopt(socket, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char*>(&error), &size);
if (r != 0 or size != sizeof(int)) {
throwIOException(e);
} else if (einProgress(error)) {
return false;
} else if (error != 0) {
throwIOException(e, socketErrorString(e, error));
}
return true;
}
bool bool
doConnect(JNIEnv* e, int s, sockaddr_in* address) doConnect(JNIEnv* e, int s, sockaddr_in* address)
{ {
@ -388,18 +419,7 @@ Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e,
jclass, jclass,
jint socket) jint socket)
{ {
int error; return doFinishConnect(e, socket);
socklen_t size = sizeof(int);
int r = getsockopt(socket, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char*>(&error), &size);
if (r != 0 or size != sizeof(int)) {
throwIOException(e);
} else if (einProgress(error)) {
return false;
} else if (error != 0) {
throwIOException(e, errorString(e, error));
}
return true;
} }
extern "C" JNIEXPORT jint JNICALL extern "C" JNIEXPORT jint JNICALL
@ -460,8 +480,10 @@ Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e,
socklen_t size = sizeof(int); socklen_t size = sizeof(int);
int r = getsockopt(socket, SOL_SOCKET, SO_ERROR, int r = getsockopt(socket, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char*>(&error), &size); reinterpret_cast<char*>(&error), &size);
if (r != 0 or size != sizeof(int) or error != 0) { if (r != 0 or size != sizeof(int)) {
throwIOException(e, errorString(e, error)); throwIOException(e);
} else if (error != 0) {
throwIOException(e, socketErrorString(e, error));
} }
} }
@ -660,6 +682,7 @@ Java_java_nio_channels_SocketSelector_natSelectUpdateInterestSet(JNIEnv *,
if (interest & (java_nio_channels_SelectionKey_OP_WRITE | if (interest & (java_nio_channels_SelectionKey_OP_WRITE |
java_nio_channels_SelectionKey_OP_CONNECT)) { java_nio_channels_SelectionKey_OP_CONNECT)) {
FD_SET(static_cast<unsigned>(socket), &(s->write)); FD_SET(static_cast<unsigned>(socket), &(s->write));
FD_SET(static_cast<unsigned>(socket), &(s->except));
if (max < socket) max = socket; if (max < socket) max = socket;
} else { } else {
FD_CLR(static_cast<unsigned>(socket), &(s->write)); FD_CLR(static_cast<unsigned>(socket), &(s->write));
@ -727,8 +750,10 @@ Java_java_nio_channels_SocketSelector_natDoSocketSelect(JNIEnv *e, jclass,
socklen_t size = sizeof(int); socklen_t size = sizeof(int);
int r = getsockopt(socket, SOL_SOCKET, SO_ERROR, int r = getsockopt(socket, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char*>(&error), &size); reinterpret_cast<char*>(&error), &size);
if (r != 0 or size != sizeof(int) or error != 0) { if (r != 0 or size != sizeof(int)) {
throwIOException(e); throwIOException(e);
} else if (error != 0) {
throwIOException(e, socketErrorString(e, error));
} }
s->control.setConnected(true); s->control.setConnected(true);
} }
@ -780,7 +805,7 @@ Java_java_nio_channels_SocketSelector_natUpdateReadySet(JNIEnv *, jclass,
} }
} }
if (FD_ISSET(socket, &(s->write))) { if (FD_ISSET(socket, &(s->write)) or FD_ISSET(socket, &(s->except))) {
if (interest & java_nio_channels_SelectionKey_OP_WRITE) { if (interest & java_nio_channels_SelectionKey_OP_WRITE) {
ready |= java_nio_channels_SelectionKey_OP_WRITE; ready |= java_nio_channels_SelectionKey_OP_WRITE;
} }