diff options
author | Guilhem Lavaux <guilhem@kaffe.org> | 2006-05-10 07:08:24 +0000 |
---|---|---|
committer | Guilhem Lavaux <guilhem@kaffe.org> | 2006-05-10 07:08:24 +0000 |
commit | 68d82e8b935385c52f40123538e6e5b0dad7dbc9 (patch) | |
tree | b95bd564d710c44882e3154712cd30b483e63ebf /native | |
parent | 754c78eb4fc80b8822d7dba21cc092efa24e8d20 (diff) | |
download | classpath-68d82e8b935385c52f40123538e6e5b0dad7dbc9.tar.gz |
2006-05-09 Guilhem Lavaux <guilhem@kaffe.org>
* 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.
Diffstat (limited to 'native')
-rw-r--r-- | native/jni/java-net/javanet.c | 2 | ||||
-rw-r--r-- | native/jni/native-lib/cpnet.c | 109 |
2 files changed, 75 insertions, 36 deletions
diff --git a/native/jni/java-net/javanet.c b/native/jni/java-net/javanet.c index daec03f6b..34a661a10 100644 --- a/native/jni/java-net/javanet.c +++ b/native/jni/java-net/javanet.c @@ -795,7 +795,7 @@ _javanet_accept (JNIEnv * env, jobject this, jobject impl) 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 diff --git a/native/jni/native-lib/cpnet.c b/native/jni/native-lib/cpnet.c index 1ab0646eb..fe114ed90 100644 --- a/native/jni/native-lib/cpnet.c +++ b/native/jni/native-lib/cpnet.c @@ -37,6 +37,7 @@ exception statement from your version. */ #include "config.h" #include <jni.h> +#include <assert.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> @@ -46,9 +47,57 @@ exception statement from your version. */ #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 @@ jint cpnet_openSocketStream(JNIEnv *env UNUSED, jint *fd, jint family) return errno; fcntl(*fd, F_SETFD, FD_CLOEXEC); + assert(*fd < FD_SETSIZE); + socketTimeouts[*fd] = SOCKET_DEFAULT_TIMEOUT; return 0; } @@ -66,6 +117,8 @@ jint cpnet_openSocketDatagram(JNIEnv *env UNUSED, jint *fd, jint family) 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_listen(JNIEnv *env UNUSED, jint fd, jint queuelen) 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 @@ jint cpnet_connect(JNIEnv *env UNUSED, jint fd, cpnet_address *addr) { 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 @@ jint cpnet_send (JNIEnv *env UNUSED, jint fd, jbyte *data, jint len, jint *bytes { 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 @@ jint cpnet_sendTo (JNIEnv *env UNUSED, jint fd, jbyte *data, jint len, cpnet_add { 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 @@ jint cpnet_recv (JNIEnv *env UNUSED, jint fd, jbyte *data, jint len, jint *bytes { ssize_t ret; + if (waitForReadable(fd) < 0) + return ETIMEDOUT; + ret = recv(fd, data, len, 0); if (ret < 0) return errno; @@ -226,6 +292,9 @@ jint cpnet_recvFrom (JNIEnv *env, jint fd, jbyte *data, jint len, cpnet_address 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 @@ jint cpnet_recvFrom (JNIEnv *env, jint fd, jbyte *data, jint len, cpnet_address } (*addr)->len = slen; - *bytes_recv = len; + *bytes_recv = ret; return 0; } @@ -306,46 +375,16 @@ jint cpnet_getLinger (JNIEnv *env UNUSED, jint fd, jint *flag, jint *value) 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) |