summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dalvik/src/main/java/dalvik/system/BlockGuard.java5
-rw-r--r--luni/src/main/java/java/net/ConnectException.java15
-rw-r--r--luni/src/main/java/java/net/PlainSocketImpl.java12
-rw-r--r--luni/src/main/java/libcore/io/BlockGuardOs.java6
-rw-r--r--luni/src/main/java/libcore/io/ForwardingOs.java1
-rw-r--r--luni/src/main/java/libcore/io/IoUtils.java31
-rw-r--r--luni/src/main/java/libcore/io/Os.java1
-rw-r--r--luni/src/main/java/libcore/io/Posix.java1
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java1
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java1
-rw-r--r--luni/src/main/native/libcore_io_Posix.cpp53
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp33
12 files changed, 96 insertions, 64 deletions
diff --git a/dalvik/src/main/java/dalvik/system/BlockGuard.java b/dalvik/src/main/java/dalvik/system/BlockGuard.java
index 119833b..fd4be27 100644
--- a/dalvik/src/main/java/dalvik/system/BlockGuard.java
+++ b/dalvik/src/main/java/dalvik/system/BlockGuard.java
@@ -195,11 +195,6 @@ public final class BlockGuard {
return mNetwork.writeDirect(fd, address, offset, count);
}
- public boolean connect(FileDescriptor fd, InetAddress inetAddress, int port) throws IOException {
- BlockGuard.getThreadPolicy().onNetwork();
- return mNetwork.connect(fd, inetAddress, port);
- }
-
public boolean isConnected(FileDescriptor fd, int timeout) throws IOException {
if (timeout != 0) {
// Greater than 0 is a timeout, but zero means "poll and return immediately".
diff --git a/luni/src/main/java/java/net/ConnectException.java b/luni/src/main/java/java/net/ConnectException.java
index 554316f..4fd478e 100644
--- a/luni/src/main/java/java/net/ConnectException.java
+++ b/luni/src/main/java/java/net/ConnectException.java
@@ -26,18 +26,23 @@ public class ConnectException extends SocketException {
private static final long serialVersionUID = 3831404271622369215L;
/**
- * This implementation does nothing.
+ * Constructs a new instance.
*/
public ConnectException() {
}
/**
- * This implementation does nothing.
- *
- * @param detailMessage
- * detail message of the exception.
+ * Constructs a new instance with the given detail message.
*/
public ConnectException(String detailMessage) {
super(detailMessage);
}
+
+ /**
+ * Constructs a new instance with the given detail message and cause.
+ * @hide
+ */
+ public ConnectException(String detailMessage, Throwable cause) {
+ super(detailMessage);
+ }
}
diff --git a/luni/src/main/java/java/net/PlainSocketImpl.java b/luni/src/main/java/java/net/PlainSocketImpl.java
index 34eec20..346984e 100644
--- a/luni/src/main/java/java/net/PlainSocketImpl.java
+++ b/luni/src/main/java/java/net/PlainSocketImpl.java
@@ -172,14 +172,10 @@ public class PlainSocketImpl extends SocketImpl {
*/
private void connect(InetAddress anAddr, int aPort, int timeout) throws IOException {
InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress.getLocalHost() : anAddr;
- try {
- if (streaming && usingSocks()) {
- socksConnect(anAddr, aPort, 0);
- } else {
- IoUtils.connect(fd, normalAddr, aPort, timeout);
- }
- } catch (ConnectException e) {
- throw new ConnectException(anAddr + " (port " + aPort + "): " + e.getMessage());
+ if (streaming && usingSocks()) {
+ socksConnect(anAddr, aPort, 0);
+ } else {
+ IoUtils.connect(fd, normalAddr, aPort, timeout);
}
super.address = normalAddr;
super.port = aPort;
diff --git a/luni/src/main/java/libcore/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index 601cc11..2c5530c 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -18,6 +18,7 @@ package libcore.io;
import dalvik.system.BlockGuard;
import java.io.FileDescriptor;
+import java.net.InetAddress;
import java.nio.ByteBuffer;
import static libcore.io.OsConstants.*;
@@ -29,6 +30,11 @@ public class BlockGuardOs extends ForwardingOs {
super(os);
}
+ public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException {
+ BlockGuard.getThreadPolicy().onNetwork();
+ os.connect(fd, address, port);
+ }
+
public void fdatasync(FileDescriptor fd) throws ErrnoException {
BlockGuard.getThreadPolicy().onWriteToDisk();
os.fdatasync(fd);
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index 68dfcf3..832ffba 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -37,6 +37,7 @@ public class ForwardingOs implements Os {
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException { os.bind(fd, address, port); }
public void chmod(String path, int mode) throws ErrnoException { os.chmod(path, mode); }
public void close(FileDescriptor fd) throws ErrnoException { os.close(fd); }
+ public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException { os.connect(fd, address, port); }
public String[] environ() { return os.environ(); }
public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException { return os.fcntlVoid(fd, cmd); }
public int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException { return os.fcntlLong(fd, cmd, arg); }
diff --git a/luni/src/main/java/libcore/io/IoUtils.java b/luni/src/main/java/libcore/io/IoUtils.java
index e2b31a7..1247ef6 100644
--- a/luni/src/main/java/libcore/io/IoUtils.java
+++ b/luni/src/main/java/libcore/io/IoUtils.java
@@ -22,6 +22,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.BindException;
+import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -238,6 +239,8 @@ public final class IoUtils {
public static boolean connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws SocketException, SocketTimeoutException {
try {
return connectErrno(fd, inetAddress, port, timeoutMs);
+ } catch (ErrnoException errnoException) {
+ throw new ConnectException(connectDetail(inetAddress, port, timeoutMs) + ": " + errnoException.getMessage(), errnoException);
} catch (SocketException ex) {
throw ex; // We don't want to doubly wrap these.
} catch (SocketTimeoutException ex) {
@@ -247,11 +250,11 @@ public final class IoUtils {
}
}
- // TODO: this is the wrong name now, but when this gets rewritten without Platform.NETWORK...
private static boolean connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws IOException {
// With no timeout, just call connect(2) directly.
if (timeoutMs == 0) {
- return Platform.NETWORK.connect(fd, inetAddress, port);
+ Libcore.os.connect(fd, inetAddress, port);
+ return true;
}
// With a timeout, we set the socket to non-blocking, connect(2), and then loop
@@ -260,18 +263,20 @@ public final class IoUtils {
long finishTimeMs = System.currentTimeMillis() + timeoutMs;
IoUtils.setBlocking(fd, false);
try {
- if (Platform.NETWORK.connect(fd, inetAddress, port)) {
- return true;
+ try {
+ Libcore.os.connect(fd, inetAddress, port);
+ return true; // We connected immediately.
+ } catch (ErrnoException errnoException) {
+ if (errnoException.errno != EINPROGRESS) {
+ throw errnoException;
+ }
+ // EINPROGRESS means we should keep trying...
}
int remainingTimeoutMs;
do {
remainingTimeoutMs = (int) (finishTimeMs - System.currentTimeMillis());
if (remainingTimeoutMs <= 0) {
- String detail = "failed to connect to " + inetAddress + " (port " + port + ")";
- if (timeoutMs > 0) {
- detail += " after " + timeoutMs + "ms";
- }
- throw new SocketTimeoutException(detail);
+ throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs));
}
} while (!Platform.NETWORK.isConnected(fd, remainingTimeoutMs));
return true; // Or we'd have thrown.
@@ -280,6 +285,14 @@ public final class IoUtils {
}
}
+ private static String connectDetail(InetAddress inetAddress, int port, int timeoutMs) {
+ String detail = "failed to connect to " + inetAddress + " (port " + port + ")";
+ if (timeoutMs > 0) {
+ detail += " after " + timeoutMs + "ms";
+ }
+ return detail;
+ }
+
/**
* Sets 'fd' to be blocking or non-blocking, according to the state of 'blocking'.
*/
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index a864176..391a6fa 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -28,6 +28,7 @@ public interface Os {
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
public void chmod(String path, int mode) throws ErrnoException;
public void close(FileDescriptor fd) throws ErrnoException;
+ public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
public String[] environ();
public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
public int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index 8640212..8451503 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -31,6 +31,7 @@ public final class Posix implements Os {
public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
public native void chmod(String path, int mode) throws ErrnoException;
public native void close(FileDescriptor fd) throws ErrnoException;
+ public native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
public native String[] environ();
public native int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
public native int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException;
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
index 6628005..23e3be3 100644
--- a/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
+++ b/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
@@ -39,7 +39,6 @@ public interface INetworkSystem {
public int writeDirect(FileDescriptor fd, int address, int offset, int count) throws IOException;
- public boolean connect(FileDescriptor fd, InetAddress inetAddress, int port) throws IOException;
public boolean isConnected(FileDescriptor fd, int timeout) throws IOException;
public int send(FileDescriptor fd, byte[] data, int offset, int length,
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
index 88b39f3..b369c6d 100644
--- a/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
+++ b/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
@@ -44,7 +44,6 @@ final class OSNetworkSystem implements INetworkSystem {
public native void accept(FileDescriptor serverFd, SocketImpl newSocket,
FileDescriptor clientFd) throws IOException;
- public native boolean connect(FileDescriptor fd, InetAddress inetAddress, int port) throws IOException;
public native boolean isConnected(FileDescriptor fd, int timeout) throws IOException;
public native void disconnectDatagram(FileDescriptor fd) throws SocketException;
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 7e2c8b6..9be8fd8 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "Posix"
+#include "AsynchronousSocketCloseMonitor.h"
#include "JNIHelp.h"
#include "JniConstants.h"
#include "JniException.h"
@@ -57,6 +58,43 @@ struct addrinfo_deleter {
}
};
+/**
+ * Used to retry syscalls that can return EINTR. This differs from TEMP_FAILURE_RETRY in that
+ * it also considers the case where the reason for failure is that another thread called
+ * Socket.close.
+ *
+ * Assumes 'JNIEnv* env' and 'jobject javaFd' (which is a java.io.FileDescriptor) are in scope.
+ *
+ * Returns the result of 'exp', though a Java exception will be pending if the result is -1.
+ *
+ * Correct usage looks like this:
+ *
+ * void Posix_syscall(JNIEnv* env, jobject javaFd, ...) {
+ * ...
+ * int fd;
+ * NET_FAILURE_RETRY("syscall", syscall(fd, ...)); // Throws on error.
+ * }
+ */
+#define NET_FAILURE_RETRY(syscall_name, exp) ({ \
+ typeof (exp) _rc = -1; \
+ do { \
+ { \
+ fd = jniGetFDFromFileDescriptor(env, javaFd); \
+ AsynchronousSocketCloseMonitor monitor(fd); \
+ _rc = (exp); \
+ } \
+ if (_rc == -1) { \
+ if (jniGetFDFromFileDescriptor(env, javaFd) == -1) { \
+ jniThrowException(env, "java/net/SocketException", "Socket closed"); \
+ break; \
+ } else if (errno != EINTR) { \
+ throwErrnoException(env, syscall_name); \
+ break; \
+ } \
+ } \
+ } while (_rc == -1); \
+ _rc; })
+
static void throwException(JNIEnv* env, jclass exceptionClass, jmethodID ctor3, jmethodID ctor2,
const char* functionName, int error) {
jthrowable cause = NULL;
@@ -290,9 +328,9 @@ static void Posix_bind(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress
if (!inetAddressToSockaddr(env, javaAddress, port, &ss)) {
return;
}
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ int fd;
const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
- throwIfMinusOne(env, "bind", TEMP_FAILURE_RETRY(bind(fd, sa, sizeof(sockaddr_storage))));
+ NET_FAILURE_RETRY("bind", bind(fd, sa, sizeof(sockaddr_storage)));
}
static void Posix_chmod(JNIEnv* env, jobject, jstring javaPath, jint mode) {
@@ -315,6 +353,16 @@ static void Posix_close(JNIEnv* env, jobject, jobject javaFd) {
throwIfMinusOne(env, "close", close(fd));
}
+static void Posix_connect(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) {
+ sockaddr_storage ss;
+ if (!inetAddressToSockaddr(env, javaAddress, port, &ss)) {
+ return;
+ }
+ int fd;
+ const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
+ NET_FAILURE_RETRY("connect", connect(fd, sa, sizeof(sockaddr_storage)));
+}
+
static jobjectArray Posix_environ(JNIEnv* env, jobject) {
extern char** environ; // Standard, but not in any header file.
return toStringArray(env, environ);
@@ -932,6 +980,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Posix, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
NATIVE_METHOD(Posix, chmod, "(Ljava/lang/String;I)V"),
NATIVE_METHOD(Posix, close, "(Ljava/io/FileDescriptor;)V"),
+ NATIVE_METHOD(Posix, connect, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
NATIVE_METHOD(Posix, environ, "()[Ljava/lang/String;"),
NATIVE_METHOD(Posix, fcntlVoid, "(Ljava/io/FileDescriptor;I)I"),
NATIVE_METHOD(Posix, fcntlLong, "(Ljava/io/FileDescriptor;IJ)I"),
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index 73901a8..150f76a 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -134,38 +134,6 @@ static jint OSNetworkSystem_write(JNIEnv* env, jobject,
return result;
}
-static jboolean OSNetworkSystem_connect(JNIEnv* env, jobject, jobject fileDescriptor, jobject inetAddr, jint port) {
- NetFd fd(env, fileDescriptor);
- if (fd.isClosed()) {
- return JNI_FALSE;
- }
-
- sockaddr_storage ss;
- if (!inetAddressToSockaddr(env, inetAddr, port, &ss)) {
- return JNI_FALSE;
- }
-
- // Initiate a connection attempt...
- int rc = connect(fd.get(), reinterpret_cast<const sockaddr*>(&ss), sizeof(sockaddr_storage));
- int connectErrno = errno;
-
- // Did we get interrupted?
- if (fd.isClosed()) {
- return JNI_FALSE;
- }
-
- // Did we fail to connect?
- if (rc == -1) {
- if (connectErrno != EINPROGRESS) {
- throwConnectException(env, connectErrno); // Permanent failure, so throw.
- }
- return JNI_FALSE;
- }
-
- // We connected straight away!
- return JNI_TRUE;
-}
-
static jboolean OSNetworkSystem_isConnected(JNIEnv* env, jobject, jobject fileDescriptor, jint timeout) {
NetFd netFd(env, fileDescriptor);
if (netFd.isClosed()) {
@@ -585,7 +553,6 @@ static void OSNetworkSystem_close(JNIEnv* env, jobject, jobject fileDescriptor)
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(OSNetworkSystem, accept, "(Ljava/io/FileDescriptor;Ljava/net/SocketImpl;Ljava/io/FileDescriptor;)V"),
NATIVE_METHOD(OSNetworkSystem, close, "(Ljava/io/FileDescriptor;)V"),
- NATIVE_METHOD(OSNetworkSystem, connect, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)Z"),
NATIVE_METHOD(OSNetworkSystem, disconnectDatagram, "(Ljava/io/FileDescriptor;)V"),
NATIVE_METHOD(OSNetworkSystem, isConnected, "(Ljava/io/FileDescriptor;I)Z"),
NATIVE_METHOD(OSNetworkSystem, read, "(Ljava/io/FileDescriptor;[BII)I"),