Hi, Here is a patch to correct the handling of socket timeouts in the NATIVE-LAYER branch. This patch relies on the select function (which is not the most portable way). A few syscalls should also be protected that way but they will come in a forthcoming patch (like connect).
ChangeLog entry: 2006-05-10 Guilhem Lavaux <[EMAIL PROTECTED]> * native/jni/native-lib/cpnet.c (cpnet_getSocketTimeout, cpnet_setSocketTimeout): Reimplemented. (waitForWritable, waitForReadable): New functions. (socketTimeouts): New static global table to hold timeouts for all socket fds. (cpnet_accept,cpnet_bind,cpnet_sendTo,cpnet_recv,cpnet_recvFrom): Added waitForXXXX safeguards to handle socket timeouts. * native/jni/java-net/javanet.c (_javanet_accept): Check for the right error value when a timeout occurs.
Index: native/jni/java-net/javanet.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/java-net/javanet.c,v retrieving revision 1.32.2.7 diff -u -r1.32.2.7 javanet.c --- native/jni/java-net/javanet.c 19 Feb 2006 17:10:27 -0000 1.32.2.7 +++ native/jni/java-net/javanet.c 10 May 2006 07:04:35 -0000 @@ -795,7 +795,7 @@ result = cpnet_accept (env, fd, &newfd); if (result != CPNATIVE_OK && result != CPNATIVE_EINTR) { - if (result == EAGAIN) + if (result == ETIMEDOUT) JCL_ThrowException (env, "java/net/SocketTimeoutException", "Timeout"); else Index: native/jni/native-lib/cpnet.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/native-lib/Attic/cpnet.c,v retrieving revision 1.1.2.3 diff -u -r1.1.2.3 cpnet.c --- native/jni/native-lib/cpnet.c 25 Mar 2006 17:08:50 -0000 1.1.2.3 +++ native/jni/native-lib/cpnet.c 10 May 2006 07:04:35 -0000 @@ -37,6 +37,7 @@ #include "config.h" #include <jni.h> +#include <assert.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> @@ -46,9 +47,57 @@ #include <netinet/tcp.h> #include <netdb.h> #include <sys/ioctl.h> +#include <sys/time.h> +#include <unistd.h> #include "cpnet.h" +#define SOCKET_DEFAULT_TIMEOUT -1 /* milliseconds */ + +static int socketTimeouts[FD_SETSIZE]; + +static jint waitForWritable(jint fd) +{ + struct timeval tv; + fd_set writeset; + int ret; + + + FD_ZERO(&writeset); + FD_SET(fd, &writeset); + if (socketTimeouts[fd] > 0) + { + tv.tv_sec = socketTimeouts[fd] / 1000; + tv.tv_usec = (socketTimeouts[fd] % 1000) * 1000; + ret = select(fd+1, NULL, &writeset, NULL, &tv); + } + else + ret = select(fd+1, NULL, &writeset, NULL, NULL); + + return (ret <= 0) ? -1 : 0; +} + +static jint waitForReadable(jint fd) +{ + struct timeval tv; + fd_set readset; + int ret; + + + FD_ZERO(&readset); + FD_SET(fd, &readset); + if (socketTimeouts[fd] > 0) + { + tv.tv_sec = socketTimeouts[fd] / 1000; + tv.tv_usec = (socketTimeouts[fd] % 1000) * 1000; + ret = select(fd+1, &readset, NULL, NULL, &tv); + } + else + ret = select(fd+1, &readset, NULL, NULL, NULL); + + return (ret <= 0) ? -1 : 0; +} + jint cpnet_openSocketStream(JNIEnv *env UNUSED, jint *fd, jint family) { *fd = socket(family, SOCK_STREAM, 0); @@ -56,6 +105,8 @@ return errno; fcntl(*fd, F_SETFD, FD_CLOEXEC); + assert(*fd < FD_SETSIZE); + socketTimeouts[*fd] = SOCKET_DEFAULT_TIMEOUT; return 0; } @@ -66,6 +117,8 @@ return errno; fcntl(*fd, F_SETFD, FD_CLOEXEC); + assert(*fd < FD_SETSIZE); + socketTimeouts[*fd] = SOCKET_DEFAULT_TIMEOUT; return 0; } @@ -101,6 +154,9 @@ jint cpnet_accept(JNIEnv *env UNUSED, jint fd, jint *newfd) { + if (waitForReadable (fd) < 0) + return ETIMEDOUT; + *newfd = accept(fd, NULL, 0); if (*newfd != 0) return errno; @@ -123,6 +179,7 @@ { int ret; + /* TODO: implement socket time out */ ret = connect(fd, (struct sockaddr *)addr->data, addr->len); if (ret != 0) return errno; @@ -187,6 +244,9 @@ { ssize_t ret; + if (waitForWritable(fd) < 0) + return ETIMEDOUT; + ret = send(fd, data, len, MSG_NOSIGNAL); if (ret < 0) return errno; @@ -200,6 +260,9 @@ { ssize_t ret; + if (waitForWritable(fd) < 0) + return ETIMEDOUT; + ret = sendto(fd, data, len, MSG_NOSIGNAL, (struct sockaddr *)addr->data, addr->len); if (ret < 0) return errno; @@ -212,6 +275,9 @@ { ssize_t ret; + if (waitForReadable(fd) < 0) + return ETIMEDOUT; + ret = recv(fd, data, len, 0); if (ret < 0) return errno; @@ -226,6 +292,9 @@ socklen_t slen = 1024; ssize_t ret; + if (waitForReadable(fd) < 0) + return ETIMEDOUT; + *addr = JCL_malloc(env, slen); slen -= sizeof(jint); @@ -238,7 +307,7 @@ } (*addr)->len = slen; - *bytes_recv = len; + *bytes_recv = ret; return 0; } @@ -306,46 +375,16 @@ return ret; } -jint cpnet_setSocketTimeout (JNIEnv *env UNUSED, jint fd UNUSED, jint value UNUSED) +jint cpnet_setSocketTimeout (JNIEnv *env UNUSED, jint fd, jint value) { -#if 0 - /* This is not really the right default implementation. This will have to - * be changed. Most OSes do not completely/rightfully support SO_TIMEOUT. - */ - struct timeval tval; - int ret; - - tval.tv_sec = value / 1000; - tval.tv_usec = (value % 1000) * 1000; - ret = setsockopt (fd, SOL_SOCKET, SO_TIMEOUT, &tval, sizeof(tval)); - if (ret != 0) - return errno; - + socketTimeouts[fd] = value; return 0; -#else - return ENOSYS; -#endif } -jint cpnet_getSocketTimeout (JNIEnv *env UNUSED, jint fd UNUSED, jint *value UNUSED) +jint cpnet_getSocketTimeout (JNIEnv *env UNUSED, jint fd, jint *value) { -#if 0 - /* This is not really the right default implementation. This will have to - * be changed. Most OSes do not completely/rightfully support SO_TIMEOUT. - */ - struct timeval tval; - int ret; - - ret = getsockopt (fd, SOL_SOCKET, SO_TIMEOUT, &tval, sizeof(tval)); - if (ret != 0) - return errno; - - *value = (tval.tv_sec * 1000) + (tval.tv_usec / 1000); - + *value = socketTimeouts[fd]; return 0; -#else - return ENOSYS; -#endif } jint cpnet_setSendBuf (JNIEnv *env UNUSED, jint fd, jint value)