Merge "Add test cases inspired by Jetty-dependent Harmony tests." into dalvik-dev
diff --git a/dalvik/src/main/java/dalvik/system/BlockGuard.java b/dalvik/src/main/java/dalvik/system/BlockGuard.java
index c25b5be..cf9789e 100644
--- a/dalvik/src/main/java/dalvik/system/BlockGuard.java
+++ b/dalvik/src/main/java/dalvik/system/BlockGuard.java
@@ -29,7 +29,6 @@
import libcore.io.Libcore;
import libcore.io.StructLinger;
import libcore.util.EmptyArray;
-import org.apache.harmony.luni.platform.INetworkSystem;
import static libcore.io.OsConstants.*;
/**
@@ -243,22 +242,4 @@
}
private BlockGuard() {}
-
- /**
- * A network wrapper that calls the policy check functions.
- */
- public static class WrappedNetworkSystem implements INetworkSystem {
- private final INetworkSystem mNetwork;
-
- public WrappedNetworkSystem(INetworkSystem network) {
- mNetwork = network;
- }
-
- public void accept(FileDescriptor serverFd, SocketImpl newSocket,
- FileDescriptor clientFd) throws IOException {
- BlockGuard.getThreadPolicy().onNetwork();
- mNetwork.accept(serverFd, newSocket, clientFd);
- tagSocketFd(clientFd);
- }
- }
}
diff --git a/luni/src/main/java/java/io/FileInputStream.java b/luni/src/main/java/java/io/FileInputStream.java
index 5b26792..6c2da1e 100644
--- a/luni/src/main/java/java/io/FileInputStream.java
+++ b/luni/src/main/java/java/io/FileInputStream.java
@@ -23,6 +23,7 @@
import java.nio.channels.FileChannel;
import java.util.Arrays;
import libcore.io.ErrnoException;
+import libcore.io.IoBridge;
import libcore.io.IoUtils;
import libcore.io.Libcore;
import libcore.io.Streams;
@@ -76,7 +77,7 @@
if (file == null) {
throw new NullPointerException("file == null");
}
- this.fd = IoUtils.open(file.getAbsolutePath(), O_RDONLY);
+ this.fd = IoBridge.open(file.getAbsolutePath(), O_RDONLY);
this.ownedFd = fd;
guard.open("close");
}
@@ -108,7 +109,7 @@
@Override
public int available() throws IOException {
- return IoUtils.available(fd);
+ return IoBridge.available(fd);
}
@Override
@@ -171,7 +172,7 @@
}
@Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
- return IoUtils.read(fd, buffer, byteOffset, byteCount);
+ return IoBridge.read(fd, buffer, byteOffset, byteCount);
}
@Override
diff --git a/luni/src/main/java/java/io/FileOutputStream.java b/luni/src/main/java/java/io/FileOutputStream.java
index 8c61281..cc57571 100644
--- a/luni/src/main/java/java/io/FileOutputStream.java
+++ b/luni/src/main/java/java/io/FileOutputStream.java
@@ -21,6 +21,7 @@
import java.nio.NioUtils;
import java.nio.channels.FileChannel;
import java.util.Arrays;
+import libcore.io.IoBridge;
import libcore.io.IoUtils;
import static libcore.io.OsConstants.*;
@@ -88,7 +89,7 @@
throw new NullPointerException("file == null");
}
this.mode = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC);
- this.fd = IoUtils.open(file.getAbsolutePath(), mode);
+ this.fd = IoBridge.open(file.getAbsolutePath(), mode);
this.ownedFd = fd;
this.guard.open("close");
}
@@ -175,7 +176,7 @@
@Override
public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException {
- IoUtils.write(fd, buffer, byteOffset, byteCount);
+ IoBridge.write(fd, buffer, byteOffset, byteCount);
}
@Override
diff --git a/luni/src/main/java/java/io/RandomAccessFile.java b/luni/src/main/java/java/io/RandomAccessFile.java
index 8517604..dde779e 100644
--- a/luni/src/main/java/java/io/RandomAccessFile.java
+++ b/luni/src/main/java/java/io/RandomAccessFile.java
@@ -24,6 +24,7 @@
import java.nio.charset.ModifiedUtf8;
import java.util.Arrays;
import libcore.io.ErrnoException;
+import libcore.io.IoBridge;
import libcore.io.IoUtils;
import libcore.io.Libcore;
import libcore.io.Memory;
@@ -114,7 +115,7 @@
throw new IllegalArgumentException("Invalid mode: " + mode);
}
this.mode = flags;
- this.fd = IoUtils.open(file.getAbsolutePath(), flags);
+ this.fd = IoBridge.open(file.getAbsolutePath(), flags);
// if we are in "rws" mode, attempt to sync file+metadata
if (syncMetadata) {
@@ -286,7 +287,7 @@
* if this file is closed or another I/O error occurs.
*/
public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
- return IoUtils.read(fd, buffer, byteOffset, byteCount);
+ return IoBridge.read(fd, buffer, byteOffset, byteCount);
}
/**
@@ -688,7 +689,7 @@
* if an I/O error occurs while writing to this file.
*/
public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException {
- IoUtils.write(fd, buffer, byteOffset, byteCount);
+ IoBridge.write(fd, buffer, byteOffset, byteCount);
// if we are in "rws" mode, attempt to sync file+metadata
if (syncMetadata) {
fd.sync();
diff --git a/luni/src/main/java/java/lang/Double.java b/luni/src/main/java/java/lang/Double.java
index 1748128..9f8ce7e 100644
--- a/luni/src/main/java/java/lang/Double.java
+++ b/luni/src/main/java/java/lang/Double.java
@@ -166,31 +166,18 @@
}
/**
- * Converts the specified double value to a binary representation conforming
- * to the IEEE 754 floating-point double precision bit layout. All
- * <em>Not-a-Number (NaN)</em> values are converted to a single NaN
- * representation ({@code 0x7ff8000000000000L}).
- *
- * @param value
- * the double value to convert.
- * @return the IEEE 754 floating-point double precision representation of
- * {@code value}.
- * @see #doubleToRawLongBits(double)
- * @see #longBitsToDouble(long)
+ * Returns an integer corresponding to the bits of the given
+ * <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> double precision
+ * {@code value}. All <em>Not-a-Number (NaN)</em> values are converted to a single NaN
+ * representation ({@code 0x7ff8000000000000L}) (compare to {@link #doubleToRawLongBits}).
*/
public static native long doubleToLongBits(double value);
/**
- * Converts the specified double value to a binary representation conforming
- * to the IEEE 754 floating-point double precision bit layout.
- * <em>Not-a-Number (NaN)</em> values are preserved.
- *
- * @param value
- * the double value to convert.
- * @return the IEEE 754 floating-point double precision representation of
- * {@code value}.
- * @see #doubleToLongBits(double)
- * @see #longBitsToDouble(long)
+ * Returns an integer corresponding to the bits of the given
+ * <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> double precision
+ * {@code value}. <em>Not-a-Number (NaN)</em> values are preserved (compare
+ * to {@link #doubleToLongBits}).
*/
public static native long doubleToRawLongBits(double value);
@@ -286,15 +273,8 @@
}
/**
- * Converts the specified IEEE 754 floating-point double precision bit
- * pattern to a Java double value.
- *
- * @param bits
- * the IEEE 754 floating-point double precision representation of
- * a double value.
- * @return the double value converted from {@code bits}.
- * @see #doubleToLongBits(double)
- * @see #doubleToRawLongBits(double)
+ * Returns the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a>
+ * double precision float corresponding to the given {@code bits}.
*/
public static native double longBitsToDouble(long bits);
@@ -313,7 +293,7 @@
* if {@code string} cannot be parsed as a double value.
*/
public static double parseDouble(String string) throws NumberFormatException {
- return org.apache.harmony.luni.util.FloatingPointParser.parseDouble(string);
+ return StringToReal.parseDouble(string);
}
@Override
@@ -421,7 +401,7 @@
*/
public static String toHexString(double d) {
/*
- * Reference: http://en.wikipedia.org/wiki/IEEE_754
+ * Reference: http://en.wikipedia.org/wiki/IEEE_754-1985
*/
if (d != d) {
return "NaN";
diff --git a/luni/src/main/java/java/lang/Float.java b/luni/src/main/java/java/lang/Float.java
index bbbb7f7..e4dc140 100644
--- a/luni/src/main/java/java/lang/Float.java
+++ b/luni/src/main/java/java/lang/Float.java
@@ -195,31 +195,18 @@
}
/**
- * Converts the specified float value to a binary representation conforming
- * to the IEEE 754 floating-point single precision bit layout. All
- * <em>Not-a-Number (NaN)</em> values are converted to a single NaN
- * representation ({@code 0x7fc00000}).
- *
- * @param value
- * the float value to convert.
- * @return the IEEE 754 floating-point single precision representation of
- * {@code value}.
- * @see #floatToRawIntBits(float)
- * @see #intBitsToFloat(int)
+ * Returns an integer corresponding to the bits of the given
+ * <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> single precision
+ * float {@code value}. All <em>Not-a-Number (NaN)</em> values are converted to a single NaN
+ * representation ({@code 0x7fc00000}) (compare to {@link #floatToRawIntBits}).
*/
public static native int floatToIntBits(float value);
/**
- * Converts the specified float value to a binary representation conforming
- * to the IEEE 754 floating-point single precision bit layout.
- * <em>Not-a-Number (NaN)</em> values are preserved.
- *
- * @param value
- * the float value to convert.
- * @return the IEEE 754 floating-point single precision representation of
- * {@code value}.
- * @see #floatToIntBits(float)
- * @see #intBitsToFloat(int)
+ * Returns an integer corresponding to the bits of the given
+ * <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> single precision
+ * float {@code value}. <em>Not-a-Number (NaN)</em> values are preserved (compare
+ * to {@link #floatToIntBits}).
*/
public static native int floatToRawIntBits(float value);
@@ -239,15 +226,8 @@
}
/**
- * Converts the specified IEEE 754 floating-point single precision bit
- * pattern to a Java float value.
- *
- * @param bits
- * the IEEE 754 floating-point single precision representation of
- * a float value.
- * @return the float value converted from {@code bits}.
- * @see #floatToIntBits(float)
- * @see #floatToRawIntBits(float)
+ * Returns the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a>
+ * single precision float corresponding to the given {@code bits}.
*/
public static native float intBitsToFloat(int bits);
@@ -318,8 +298,7 @@
* @since 1.2
*/
public static float parseFloat(String string) throws NumberFormatException {
- return org.apache.harmony.luni.util.FloatingPointParser
- .parseFloat(string);
+ return StringToReal.parseFloat(string);
}
@Override
@@ -429,7 +408,7 @@
*/
public static String toHexString(float f) {
/*
- * Reference: http://en.wikipedia.org/wiki/IEEE_754
+ * Reference: http://en.wikipedia.org/wiki/IEEE_754-1985
*/
if (f != f) {
return "NaN";
diff --git a/luni/src/main/java/org/apache/harmony/luni/util/HexStringParser.java b/luni/src/main/java/java/lang/HexStringParser.java
similarity index 99%
rename from luni/src/main/java/org/apache/harmony/luni/util/HexStringParser.java
rename to luni/src/main/java/java/lang/HexStringParser.java
index 9e20a16..8593b99 100644
--- a/luni/src/main/java/org/apache/harmony/luni/util/HexStringParser.java
+++ b/luni/src/main/java/java/lang/HexStringParser.java
@@ -15,13 +15,17 @@
* limitations under the License.
*/
-package org.apache.harmony.luni.util;
+package java.lang;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
* Parses hex string to a single or double precision floating point number.
+ *
+ * TODO: rewrite this!
+ *
+ * @hide
*/
final class HexStringParser {
diff --git a/luni/src/main/java/java/lang/ProcessManager.java b/luni/src/main/java/java/lang/ProcessManager.java
index cdcbb8a..d65d04d 100644
--- a/luni/src/main/java/java/lang/ProcessManager.java
+++ b/luni/src/main/java/java/lang/ProcessManager.java
@@ -31,31 +31,13 @@
import libcore.io.ErrnoException;
import libcore.io.IoUtils;
import libcore.io.Libcore;
+import libcore.util.MutableInt;
import static libcore.io.OsConstants.*;
/**
* Manages child processes.
*/
final class ProcessManager {
-
- /**
- * constant communicated from native code indicating that a
- * child died, but it was unable to determine the status
- */
- private static final int WAIT_STATUS_UNKNOWN = -1;
-
- /**
- * constant communicated from native code indicating that there
- * are currently no children to wait for
- */
- private static final int WAIT_STATUS_NO_CHILDREN = -2;
-
- /**
- * constant communicated from native code indicating that a wait()
- * call returned -1 and set an undocumented (and hence unexpected) errno
- */
- private static final int WAIT_STATUS_STRANGE_ERRNO = -3;
-
/**
* Map from pid to Process. We keep weak references to the Process objects
* and clean up the entries when no more external references are left. The
@@ -71,13 +53,13 @@
private ProcessManager() {
// Spawn a thread to listen for signals from child processes.
- Thread processThread = new Thread(ProcessManager.class.getName()) {
+ Thread reaperThread = new Thread(ProcessManager.class.getName()) {
@Override public void run() {
- watchChildren(ProcessManager.this);
+ watchChildren();
}
};
- processThread.setDaemon(true);
- processThread.start();
+ reaperThread.setDaemon(true);
+ reaperThread.start();
}
/**
@@ -94,10 +76,40 @@
}
/**
- * Listens for signals from processes and calls back to
- * {@link #onExit(int,int)}.
+ * Loops indefinitely and calls ProcessManager.onExit() when children exit.
*/
- private static native void watchChildren(ProcessManager manager);
+ private void watchChildren() {
+ MutableInt status = new MutableInt(-1);
+ while (true) {
+ try {
+ // Wait for children in our process group.
+ int pid = Libcore.os.waitpid(0, status, 0);
+
+ // Work out what onExit wants to hear.
+ int exitValue;
+ if (WIFEXITED(status.value)) {
+ exitValue = WEXITSTATUS(status.value);
+ } else if (WIFSIGNALED(status.value)) {
+ exitValue = WTERMSIG(status.value);
+ } else if (WIFSTOPPED(status.value)) {
+ exitValue = WSTOPSIG(status.value);
+ } else {
+ throw new AssertionError("unexpected status from waitpid: " + status.value);
+ }
+
+ onExit(pid, exitValue);
+ } catch (ErrnoException errnoException) {
+ if (errnoException.errno == ECHILD) {
+ // Expected errno: there are no children to wait for.
+ // onExit will sleep until it is informed of another child coming to life.
+ waitForMoreChildren();
+ continue;
+ } else {
+ throw errnoException;
+ }
+ }
+ }
+ }
/**
* Called by {@link #watchChildren()} when a child process exits.
@@ -107,38 +119,10 @@
*/
private void onExit(int pid, int exitValue) {
ProcessReference processReference = null;
-
synchronized (processReferences) {
cleanUp();
- if (pid >= 0) {
- processReference = processReferences.remove(pid);
- } else if (exitValue == WAIT_STATUS_NO_CHILDREN) {
- if (processReferences.isEmpty()) {
- /*
- * There are no eligible children; wait for one to be
- * added. The wait() will return due to the
- * notifyAll() call below.
- */
- try {
- processReferences.wait();
- } catch (InterruptedException ex) {
- // This should never happen.
- throw new AssertionError("unexpected interrupt");
- }
- } else {
- /*
- * A new child was spawned just before we entered
- * the synchronized block. We can just fall through
- * without doing anything special and land back in
- * the native wait().
- */
- }
- } else {
- // Something weird is happening; abort!
- throw new AssertionError("unexpected wait() behavior");
- }
+ processReference = processReferences.remove(pid);
}
-
if (processReference != null) {
ProcessImpl process = processReference.get();
if (process != null) {
@@ -147,6 +131,31 @@
}
}
+ private void waitForMoreChildren() {
+ synchronized (processReferences) {
+ if (processReferences.isEmpty()) {
+ /*
+ * There are no eligible children; wait for one to be
+ * added. The wait() will return due to the
+ * notifyAll() call below.
+ */
+ try {
+ processReferences.wait();
+ } catch (InterruptedException ex) {
+ // This should never happen.
+ throw new AssertionError("unexpected interrupt");
+ }
+ } else {
+ /*
+ * A new child was spawned just before we entered
+ * the synchronized block. We can just fall through
+ * without doing anything special and land back in
+ * the native waitpid().
+ */
+ }
+ }
+ }
+
/**
* Executes a native process. Fills in in, out, and err and returns the
* new process ID upon success.
diff --git a/luni/src/main/java/org/apache/harmony/luni/util/FloatingPointParser.java b/luni/src/main/java/java/lang/StringToReal.java
similarity index 98%
rename from luni/src/main/java/org/apache/harmony/luni/util/FloatingPointParser.java
rename to luni/src/main/java/java/lang/StringToReal.java
index e08e560..97f6d6b 100644
--- a/luni/src/main/java/org/apache/harmony/luni/util/FloatingPointParser.java
+++ b/luni/src/main/java/java/lang/StringToReal.java
@@ -15,14 +15,14 @@
* limitations under the License.
*/
-package org.apache.harmony.luni.util;
-
+package java.lang;
/**
* Used to parse a string and return either a single or double precision
* floating point number.
+ * @hide
*/
-public final class FloatingPointParser {
+final class StringToReal {
private static final class StringExponentPair {
String s;
diff --git a/luni/src/main/java/java/math/MathContext.java b/luni/src/main/java/java/math/MathContext.java
index 24ccb29..6f3f1ed 100644
--- a/luni/src/main/java/java/math/MathContext.java
+++ b/luni/src/main/java/java/math/MathContext.java
@@ -30,21 +30,21 @@
private static final long serialVersionUID = 5579720004786848255L;
/**
- * A {@code MathContext} which corresponds to the IEEE 754r quadruple
+ * A {@code MathContext} which corresponds to the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> quadruple
* decimal precision format: 34 digit precision and
* {@link RoundingMode#HALF_EVEN} rounding.
*/
public static final MathContext DECIMAL128 = new MathContext(34, RoundingMode.HALF_EVEN);
/**
- * A {@code MathContext} which corresponds to the IEEE 754r single decimal
+ * A {@code MathContext} which corresponds to the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> single decimal
* precision format: 7 digit precision and {@link RoundingMode#HALF_EVEN}
* rounding.
*/
public static final MathContext DECIMAL32 = new MathContext(7, RoundingMode.HALF_EVEN);
/**
- * A {@code MathContext} which corresponds to the IEEE 754r double decimal
+ * A {@code MathContext} which corresponds to the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> double decimal
* precision format: 16 digit precision and {@link RoundingMode#HALF_EVEN}
* rounding.
*/
diff --git a/luni/src/main/java/java/net/DatagramSocketImpl.java b/luni/src/main/java/java/net/DatagramSocketImpl.java
index 4485b18..6e706c3 100644
--- a/luni/src/main/java/java/net/DatagramSocketImpl.java
+++ b/luni/src/main/java/java/net/DatagramSocketImpl.java
@@ -19,7 +19,7 @@
import java.io.FileDescriptor;
import java.io.IOException;
-import libcore.io.IoUtils;
+import libcore.io.IoBridge;
/**
* The abstract superclass for datagram and multicast socket implementations.
@@ -85,7 +85,7 @@
* Returns the local address to which the socket is bound.
*/
InetAddress getLocalAddress() {
- return IoUtils.getSocketLocalAddress(fd);
+ return IoBridge.getSocketLocalAddress(fd);
}
/**
diff --git a/luni/src/main/java/java/net/InetAddress.java b/luni/src/main/java/java/net/InetAddress.java
index 9541bb9..56eb1f4 100644
--- a/luni/src/main/java/java/net/InetAddress.java
+++ b/luni/src/main/java/java/net/InetAddress.java
@@ -34,7 +34,7 @@
import libcore.io.ErrnoException;
import libcore.io.GaiException;
import libcore.io.Libcore;
-import libcore.io.IoUtils;
+import libcore.io.IoBridge;
import libcore.io.Memory;
import libcore.io.StructAddrinfo;
import static libcore.io.OsConstants.*;
@@ -807,13 +807,13 @@
}
private boolean isReachableByTCP(InetAddress destination, InetAddress source, int timeout) throws IOException {
- FileDescriptor fd = IoUtils.socket(true);
+ FileDescriptor fd = IoBridge.socket(true);
boolean reached = false;
try {
if (source != null) {
- IoUtils.bind(fd, source, 0);
+ IoBridge.bind(fd, source, 0);
}
- IoUtils.connect(fd, destination, 7, timeout);
+ IoBridge.connect(fd, destination, 7, timeout);
reached = true;
} catch (IOException e) {
if (e.getCause() instanceof ErrnoException) {
@@ -822,7 +822,7 @@
}
}
- IoUtils.closeSocket(fd);
+ IoBridge.closeSocket(fd);
return reached;
}
diff --git a/luni/src/main/java/java/net/PlainDatagramSocketImpl.java b/luni/src/main/java/java/net/PlainDatagramSocketImpl.java
index 4301f79..f27db94 100644
--- a/luni/src/main/java/java/net/PlainDatagramSocketImpl.java
+++ b/luni/src/main/java/java/net/PlainDatagramSocketImpl.java
@@ -28,7 +28,7 @@
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
-import libcore.io.IoUtils;
+import libcore.io.IoBridge;
import libcore.io.Libcore;
import libcore.io.StructGroupReq;
import libcore.util.EmptyArray;
@@ -63,13 +63,12 @@
fd = new FileDescriptor();
}
- @Override
- public void bind(int port, InetAddress address) throws SocketException {
- IoUtils.bind(fd, address, port);
+ @Override public void bind(int port, InetAddress address) throws SocketException {
+ IoBridge.bind(fd, address, port);
if (port != 0) {
localPort = port;
} else {
- localPort = IoUtils.getSocketLocalPort(fd);
+ localPort = IoBridge.getSocketLocalPort(fd);
}
try {
setOption(SocketOptions.SO_BROADCAST, Boolean.TRUE);
@@ -81,14 +80,14 @@
public synchronized void close() {
guard.close();
try {
- IoUtils.closeSocket(fd);
+ IoBridge.closeSocket(fd);
} catch (IOException ignored) {
}
}
@Override
public void create() throws SocketException {
- this.fd = IoUtils.socket(false);
+ this.fd = IoBridge.socket(false);
}
@Override protected void finalize() throws Throwable {
@@ -103,12 +102,12 @@
}
@Override public Object getOption(int option) throws SocketException {
- return IoUtils.getSocketOption(fd, option);
+ return IoBridge.getSocketOption(fd, option);
}
@Override
public int getTimeToLive() throws IOException {
- return (Integer) getOption(IoUtils.JAVA_IP_MULTICAST_TTL);
+ return (Integer) getOption(IoBridge.JAVA_IP_MULTICAST_TTL);
}
@Override
@@ -123,27 +122,27 @@
@Override
public void join(InetAddress addr) throws IOException {
- setOption(IoUtils.JAVA_MCAST_JOIN_GROUP, makeGroupReq(addr, null));
+ setOption(IoBridge.JAVA_MCAST_JOIN_GROUP, makeGroupReq(addr, null));
}
@Override
public void joinGroup(SocketAddress addr, NetworkInterface netInterface) throws IOException {
if (addr instanceof InetSocketAddress) {
InetAddress groupAddr = ((InetSocketAddress) addr).getAddress();
- setOption(IoUtils.JAVA_MCAST_JOIN_GROUP, makeGroupReq(groupAddr, netInterface));
+ setOption(IoBridge.JAVA_MCAST_JOIN_GROUP, makeGroupReq(groupAddr, netInterface));
}
}
@Override
public void leave(InetAddress addr) throws IOException {
- setOption(IoUtils.JAVA_MCAST_LEAVE_GROUP, makeGroupReq(addr, null));
+ setOption(IoBridge.JAVA_MCAST_LEAVE_GROUP, makeGroupReq(addr, null));
}
@Override
public void leaveGroup(SocketAddress addr, NetworkInterface netInterface) throws IOException {
if (addr instanceof InetSocketAddress) {
InetAddress groupAddr = ((InetSocketAddress) addr).getAddress();
- setOption(IoUtils.JAVA_MCAST_LEAVE_GROUP, makeGroupReq(groupAddr, netInterface));
+ setOption(IoBridge.JAVA_MCAST_LEAVE_GROUP, makeGroupReq(groupAddr, netInterface));
}
}
@@ -158,7 +157,7 @@
}
private void doRecv(DatagramPacket pack, int flags) throws IOException {
- IoUtils.recvfrom(false, fd, pack.getData(), pack.getOffset(), pack.getLength(), flags, pack, isNativeConnected);
+ IoBridge.recvfrom(false, fd, pack.getData(), pack.getOffset(), pack.getLength(), flags, pack, isNativeConnected);
if (isNativeConnected) {
updatePacketRecvAddress(pack);
}
@@ -179,16 +178,16 @@
public void send(DatagramPacket packet) throws IOException {
int port = isNativeConnected ? 0 : packet.getPort();
InetAddress address = isNativeConnected ? null : packet.getAddress();
- IoUtils.sendto(fd, packet.getData(), packet.getOffset(), packet.getLength(), 0, address, port);
+ IoBridge.sendto(fd, packet.getData(), packet.getOffset(), packet.getLength(), 0, address, port);
}
public void setOption(int option, Object value) throws SocketException {
- IoUtils.setSocketOption(fd, option, value);
+ IoBridge.setSocketOption(fd, option, value);
}
@Override
public void setTimeToLive(int ttl) throws IOException {
- setOption(IoUtils.JAVA_IP_MULTICAST_TTL, Integer.valueOf(ttl));
+ setOption(IoBridge.JAVA_IP_MULTICAST_TTL, Integer.valueOf(ttl));
}
@Override
@@ -198,7 +197,7 @@
@Override
public void connect(InetAddress inetAddr, int port) throws SocketException {
- IoUtils.connect(fd, inetAddr, port); // Throws on failure.
+ IoBridge.connect(fd, inetAddr, port); // Throws on failure.
try {
connectedAddress = InetAddress.getByAddress(inetAddr.getAddress());
} catch (UnknownHostException e) {
diff --git a/luni/src/main/java/java/net/PlainSocketImpl.java b/luni/src/main/java/java/net/PlainSocketImpl.java
index 1ab4cdf..20dfcc2 100644
--- a/luni/src/main/java/java/net/PlainSocketImpl.java
+++ b/luni/src/main/java/java/net/PlainSocketImpl.java
@@ -34,11 +34,10 @@
import java.nio.ByteOrder;
import java.util.Arrays;
import libcore.io.ErrnoException;
-import libcore.io.IoUtils;
+import libcore.io.IoBridge;
import libcore.io.Libcore;
import libcore.io.Memory;
import libcore.io.Streams;
-import org.apache.harmony.luni.platform.Platform;
import static libcore.io.OsConstants.*;
/**
@@ -93,12 +92,28 @@
((PlainSocketImpl) newImpl).socksAccept();
return;
}
- Platform.NETWORK.accept(fd, newImpl, newImpl.getFileDescriptor());
+
+ try {
+ InetSocketAddress peerAddress = new InetSocketAddress();
+ FileDescriptor clientFd = Libcore.os.accept(fd, peerAddress);
+
+ // TODO: we can't just set newImpl.fd to clientFd because a nio SocketChannel may
+ // be sharing the FileDescriptor. http://b//4452981.
+ newImpl.fd.setInt$(clientFd.getInt$());
+
+ newImpl.address = peerAddress.getAddress();
+ newImpl.port = peerAddress.getPort();
+ } catch (ErrnoException errnoException) {
+ if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
+ throw new SocketTimeoutException(errnoException);
+ }
+ throw errnoException.rethrowAsSocketException();
+ }
// Reset the client's inherited read timeout to the Java-specified default of 0.
newImpl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(0));
- newImpl.localport = IoUtils.getSocketLocalPort(newImpl.fd);
+ newImpl.localport = IoBridge.getSocketLocalPort(newImpl.fd);
}
private boolean usingSocks() {
@@ -128,24 +143,23 @@
if (shutdownInput) {
return 0;
}
- return IoUtils.available(fd);
+ return IoBridge.available(fd);
}
- @Override
- protected void bind(InetAddress address, int port) throws IOException {
- IoUtils.bind(fd, address, port);
+ @Override protected void bind(InetAddress address, int port) throws IOException {
+ IoBridge.bind(fd, address, port);
this.address = address;
if (port != 0) {
this.localport = port;
} else {
- this.localport = IoUtils.getSocketLocalPort(fd);
+ this.localport = IoBridge.getSocketLocalPort(fd);
}
}
@Override
protected synchronized void close() throws IOException {
guard.close();
- IoUtils.closeSocket(fd);
+ IoBridge.closeSocket(fd);
}
@Override
@@ -175,7 +189,7 @@
if (streaming && usingSocks()) {
socksConnect(anAddr, aPort, 0);
} else {
- IoUtils.connect(fd, normalAddr, aPort, timeout);
+ IoBridge.connect(fd, normalAddr, aPort, timeout);
}
super.address = normalAddr;
super.port = aPort;
@@ -184,7 +198,7 @@
@Override
protected void create(boolean streaming) throws IOException {
this.streaming = streaming;
- this.fd = IoUtils.socket(streaming);
+ this.fd = IoBridge.socket(streaming);
}
@Override protected void finalize() throws Throwable {
@@ -228,7 +242,7 @@
}
@Override public Object getOption(int option) throws SocketException {
- return IoUtils.getSocketOption(fd, option);
+ return IoBridge.getSocketOption(fd, option);
}
@Override protected synchronized OutputStream getOutputStream() throws IOException {
@@ -272,7 +286,7 @@
@Override
public void setOption(int option, Object value) throws SocketException {
- IoUtils.setSocketOption(fd, option, value);
+ IoBridge.setSocketOption(fd, option, value);
}
/**
@@ -307,7 +321,7 @@
*/
private void socksConnect(InetAddress applicationServerAddress, int applicationServerPort, int timeout) throws IOException {
try {
- IoUtils.connect(fd, socksGetServerAddress(), socksGetServerPort(), timeout);
+ IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort(), timeout);
} catch (Exception e) {
throw new SocketException("SOCKS connection failed", e);
}
@@ -372,7 +386,7 @@
*/
private void socksBind() throws IOException {
try {
- IoUtils.connect(fd, socksGetServerAddress(), socksGetServerPort());
+ IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort());
} catch (Exception e) {
throw new IOException("Unable to connect to SOCKS server", e);
}
@@ -471,7 +485,7 @@
if (shutdownInput) {
return -1;
}
- int readCount = IoUtils.recvfrom(true, fd, buffer, offset, byteCount, 0, null, false);
+ int readCount = IoBridge.recvfrom(true, fd, buffer, offset, byteCount, 0, null, false);
// Return of zero bytes for a blocking socket means a timeout occurred
if (readCount == 0) {
throw new SocketTimeoutException();
@@ -490,7 +504,7 @@
Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
if (streaming) {
while (byteCount > 0) {
- int bytesWritten = IoUtils.sendto(fd, buffer, offset, byteCount, 0, null, 0);
+ int bytesWritten = IoBridge.sendto(fd, buffer, offset, byteCount, 0, null, 0);
byteCount -= bytesWritten;
offset += bytesWritten;
}
@@ -498,7 +512,7 @@
// Unlike writes to a streaming socket, writes to a datagram
// socket are all-or-nothing, so we don't need a loop here.
// http://code.google.com/p/android/issues/detail?id=15304
- IoUtils.sendto(fd, buffer, offset, byteCount, 0, address, port);
+ IoBridge.sendto(fd, buffer, offset, byteCount, 0, address, port);
}
}
}
diff --git a/luni/src/main/java/java/net/Socket.java b/luni/src/main/java/java/net/Socket.java
index 06e1ab3..f7788b5 100644
--- a/luni/src/main/java/java/net/Socket.java
+++ b/luni/src/main/java/java/net/Socket.java
@@ -22,7 +22,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.SocketChannel;
-import libcore.io.IoUtils;
+import libcore.io.IoBridge;
/**
* Provides a client-side TCP socket.
@@ -947,7 +947,7 @@
}
private void cacheLocalAddress() {
- this.localAddress = IoUtils.getSocketLocalAddress(impl.fd);
+ this.localAddress = IoBridge.getSocketLocalAddress(impl.fd);
}
/**
diff --git a/luni/src/main/java/java/net/SocketTimeoutException.java b/luni/src/main/java/java/net/SocketTimeoutException.java
index 30417d5..8f8ef82 100644
--- a/luni/src/main/java/java/net/SocketTimeoutException.java
+++ b/luni/src/main/java/java/net/SocketTimeoutException.java
@@ -41,6 +41,14 @@
}
/**
+ * Constructs a new instance with given cause.
+ * @hide internal use only
+ */
+ public SocketTimeoutException(Throwable cause) {
+ super(null, cause);
+ }
+
+ /**
* Constructs a new instance with given detail message and cause.
* @hide internal use only
*/
diff --git a/luni/src/main/java/java/nio/DatagramChannelImpl.java b/luni/src/main/java/java/nio/DatagramChannelImpl.java
index f0b9eb0..7874af6 100644
--- a/luni/src/main/java/java/nio/DatagramChannelImpl.java
+++ b/luni/src/main/java/java/nio/DatagramChannelImpl.java
@@ -37,6 +37,7 @@
import java.nio.channels.spi.SelectorProvider;
import java.util.Arrays;
import libcore.io.ErrnoException;
+import libcore.io.IoBridge;
import libcore.io.IoUtils;
import libcore.io.Libcore;
import libcore.util.EmptyArray;
@@ -71,7 +72,7 @@
*/
protected DatagramChannelImpl(SelectorProvider selectorProvider) throws IOException {
super(selectorProvider);
- fd = IoUtils.socket(false);
+ fd = IoBridge.socket(false);
}
/*
@@ -100,7 +101,7 @@
* Returns the local address to which the socket is bound.
*/
InetAddress getLocalAddress() {
- return IoUtils.getSocketLocalAddress(fd);
+ return IoBridge.getSocketLocalAddress(fd);
}
/**
@@ -127,7 +128,7 @@
InetSocketAddress inetSocketAddress = SocketChannelImpl.validateAddress(address);
try {
begin();
- IoUtils.connect(fd, inetSocketAddress.getAddress(), inetSocketAddress.getPort());
+ IoBridge.connect(fd, inetSocketAddress.getAddress(), inetSocketAddress.getPort());
} catch (ConnectException e) {
// ConnectException means connect fail, not exception
} finally {
@@ -205,7 +206,7 @@
receivePacket = new DatagramPacket(new byte[target.remaining()], target.remaining());
}
do {
- received = IoUtils.recvfrom(false, fd, receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength(), 0, receivePacket, isConnected());
+ received = IoBridge.recvfrom(false, fd, receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength(), 0, receivePacket, isConnected());
if (receivePacket != null && receivePacket.getAddress() != null) {
if (received > 0) {
if (target.hasArray()) {
@@ -228,7 +229,7 @@
int oldposition = target.position();
int received = 0;
do {
- received = IoUtils.recvfrom(false, fd, target, 0, receivePacket, isConnected());
+ received = IoBridge.recvfrom(false, fd, target, 0, receivePacket, isConnected());
if (receivePacket != null && receivePacket.getAddress() != null) {
// copy the data of received packet
if (received > 0) {
@@ -260,7 +261,7 @@
try {
begin();
int oldPosition = source.position();
- sendCount = IoUtils.sendto(fd, source, 0, isa.getAddress(), isa.getPort());
+ sendCount = IoBridge.sendto(fd, source, 0, isa.getAddress(), isa.getPort());
source.position(oldPosition + sendCount);
} finally {
end(sendCount >= 0);
@@ -333,7 +334,7 @@
int readCount = 0;
try {
begin();
- readCount = IoUtils.recvfrom(false, fd, dst, 0, null, isConnected());
+ readCount = IoBridge.recvfrom(false, fd, dst, 0, null, isConnected());
} catch (InterruptedIOException e) {
// InterruptedIOException will be thrown when timeout.
return 0;
@@ -396,7 +397,7 @@
int result = 0;
try {
begin();
- result = IoUtils.sendto(fd, buf, 0, null, 0);
+ result = IoBridge.sendto(fd, buf, 0, null, 0);
} finally {
end(result > 0);
}
@@ -409,7 +410,7 @@
if (socket != null && !socket.isClosed()) {
socket.close();
} else {
- IoUtils.closeSocket(fd);
+ IoBridge.closeSocket(fd);
}
}
diff --git a/luni/src/main/java/java/nio/FileChannelImpl.java b/luni/src/main/java/java/nio/FileChannelImpl.java
index acc3725..c1eb8c2 100644
--- a/luni/src/main/java/java/nio/FileChannelImpl.java
+++ b/luni/src/main/java/java/nio/FileChannelImpl.java
@@ -238,9 +238,6 @@
public long position() throws IOException {
checkOpen();
- if ((mode & O_APPEND) != 0) {
- return size();
- }
try {
return Libcore.os.lseek(fd, 0L, SEEK_CUR);
} catch (ErrnoException errnoException) {
@@ -482,9 +479,6 @@
public int write(ByteBuffer buffer) throws IOException {
checkOpen();
checkWritable();
- if ((mode & O_APPEND) != 0) {
- position(size());
- }
return writeImpl(buffer);
}
diff --git a/luni/src/main/java/java/nio/SelectorImpl.java b/luni/src/main/java/java/nio/SelectorImpl.java
index d1df600..dfd3270 100644
--- a/luni/src/main/java/java/nio/SelectorImpl.java
+++ b/luni/src/main/java/java/nio/SelectorImpl.java
@@ -36,6 +36,7 @@
import java.util.Set;
import java.util.UnsafeArrayList;
import libcore.io.ErrnoException;
+import libcore.io.IoBridge;
import libcore.io.IoUtils;
import libcore.io.Libcore;
import libcore.io.StructPollfd;
@@ -227,7 +228,7 @@
if (pollFds.get(0).revents == POLLIN) {
// Read bytes from the wakeup pipe until the pipe is empty.
byte[] buffer = new byte[8];
- while (IoUtils.read(wakeupIn, buffer, 0, 1) > 0) {
+ while (IoBridge.read(wakeupIn, buffer, 0, 1) > 0) {
}
}
diff --git a/luni/src/main/java/java/nio/SocketChannelImpl.java b/luni/src/main/java/java/nio/SocketChannelImpl.java
index 56c5709..c659299 100644
--- a/luni/src/main/java/java/nio/SocketChannelImpl.java
+++ b/luni/src/main/java/java/nio/SocketChannelImpl.java
@@ -44,6 +44,7 @@
import java.util.Arrays;
import libcore.io.ErrnoException;
import libcore.io.Libcore;
+import libcore.io.IoBridge;
import libcore.io.IoUtils;
import static libcore.io.OsConstants.*;
@@ -98,7 +99,7 @@
public SocketChannelImpl(SelectorProvider selectorProvider, boolean connect) throws IOException {
super(selectorProvider);
status = SOCKET_STATUS_UNCONNECTED;
- fd = (connect ? IoUtils.socket(true) : new FileDescriptor());
+ fd = (connect ? IoBridge.socket(true) : new FileDescriptor());
}
/*
@@ -164,7 +165,7 @@
if (isBlocking()) {
begin();
}
- finished = IoUtils.connect(fd, normalAddr, port);
+ finished = IoBridge.connect(fd, normalAddr, port);
isBound = finished;
} catch (IOException e) {
if (e instanceof ConnectException && !isBlocking()) {
@@ -228,7 +229,7 @@
begin();
InetAddress inetAddress = connectAddress.getAddress();
int port = connectAddress.getPort();
- finished = IoUtils.isConnected(fd, inetAddress, port, 0, 0); // Return immediately.
+ finished = IoBridge.isConnected(fd, inetAddress, port, 0, 0); // Return immediately.
isBound = finished;
} catch (ConnectException e) {
if (isOpen()) {
@@ -296,7 +297,7 @@
if (isBlocking()) {
begin();
}
- readCount = IoUtils.recvfrom(true, fd, dst, 0, null, false);
+ readCount = IoBridge.recvfrom(true, fd, dst, 0, null, false);
dst.position(dst.position() + readCount);
} finally {
if (isBlocking()) {
@@ -358,7 +359,7 @@
if (isBlocking()) {
begin();
}
- writeCount = IoUtils.sendto(fd, src, 0, null, 0);
+ writeCount = IoBridge.sendto(fd, src, 0, null, 0);
src.position(src.position() + writeCount);
} finally {
if (isBlocking()) {
@@ -431,7 +432,7 @@
if (socket != null && !socket.isClosed()) {
socket.close();
} else {
- IoUtils.closeSocket(fd);
+ IoBridge.closeSocket(fd);
}
}
}
diff --git a/luni/src/main/java/libcore/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index 014b1cd..e77e0bb 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -32,6 +32,20 @@
super(os);
}
+ private FileDescriptor tagSocket(FileDescriptor fd) {
+ try {
+ BlockGuard.tagSocketFd(fd);
+ return fd;
+ } catch (SocketException e) {
+ throw new ErrnoException("socket", EINVAL, e);
+ }
+ }
+
+ @Override public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException {
+ BlockGuard.getThreadPolicy().onNetwork();
+ return tagSocket(os.accept(fd, peerAddress));
+ }
+
@Override public void close(FileDescriptor fd) throws ErrnoException {
// TODO: is there a way to avoid calling getsockopt(2) on non-socket fds?
if (isLingerSocket(fd)) {
@@ -108,14 +122,14 @@
return os.readv(fd, buffers, offsets, byteCounts);
}
- @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress inetSocketAddress) throws ErrnoException {
+ @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException {
BlockGuard.getThreadPolicy().onNetwork();
- return os.recvfrom(fd, buffer, flags, inetSocketAddress);
+ return os.recvfrom(fd, buffer, flags, srcAddress);
}
- @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress inetSocketAddress) throws ErrnoException {
+ @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException {
BlockGuard.getThreadPolicy().onNetwork();
- return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, inetSocketAddress);
+ return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress);
}
@Override public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException {
@@ -132,13 +146,7 @@
}
@Override public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException {
- final FileDescriptor fd = os.socket(domain, type, protocol);
- try {
- BlockGuard.tagSocketFd(fd);
- } catch (SocketException e) {
- throw new ErrnoException("socket", EINVAL, e);
- }
- return fd;
+ return tagSocket(os.socket(domain, type, protocol));
}
@Override public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index 7e807ef..f205994 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -34,6 +34,7 @@
this.os = os;
}
+ public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException { return os.accept(fd, peerAddress); }
public boolean access(String path, int mode) throws ErrnoException { return os.access(path, mode); }
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); }
@@ -90,8 +91,8 @@
public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { return os.read(fd, buffer); }
public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { return os.read(fd, bytes, byteOffset, byteCount); }
public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException { return os.readv(fd, buffers, offsets, byteCounts); }
- public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress inetSocketAddress) throws ErrnoException { return os.recvfrom(fd, buffer, flags, inetSocketAddress); }
- public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress inetSocketAddress) throws ErrnoException { return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, inetSocketAddress); }
+ public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException { return os.recvfrom(fd, buffer, flags, srcAddress); }
+ public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException { return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress); }
public void remove(String path) throws ErrnoException { os.remove(path); }
public void rename(String oldPath, String newPath) throws ErrnoException { os.rename(oldPath, newPath); }
public long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException { return os.sendfile(outFd, inFd, inOffset, byteCount); }
@@ -116,6 +117,7 @@
public void symlink(String oldPath, String newPath) throws ErrnoException { os.symlink(oldPath, newPath); }
public long sysconf(int name) { return os.sysconf(name); }
public StructUtsname uname() throws ErrnoException { return os.uname(); }
+ public int waitpid(int pid, MutableInt status, int options) throws ErrnoException { return os.waitpid(pid, status, options); }
public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { return os.write(fd, buffer); }
public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { return os.write(fd, bytes, byteOffset, byteCount); }
public int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException { return os.writev(fd, buffers, offsets, byteCounts); }
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
new file mode 100644
index 0000000..c26b565
--- /dev/null
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.io;
+
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.BindException;
+import java.net.ConnectException;
+import java.net.DatagramPacket;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.PortUnreachableException;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketOptions;
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.util.MutableInt;
+import static libcore.io.OsConstants.*;
+
+/**
+ * Implements java.io/java.net/java.nio semantics in terms of the underlying POSIX system calls.
+ */
+public final class IoBridge {
+
+ private IoBridge() {
+ }
+
+ public static int available(FileDescriptor fd) throws IOException {
+ try {
+ MutableInt available = new MutableInt(0);
+ int rc = Libcore.os.ioctlInt(fd, FIONREAD, available);
+ if (available.value < 0) {
+ // If the fd refers to a regular file, the result is the difference between
+ // the file size and the file position. This may be negative if the position
+ // is past the end of the file. If the fd refers to a special file masquerading
+ // as a regular file, the result may be negative because the special file
+ // may appear to have zero size and yet a previous read call may have
+ // read some amount of data and caused the file position to be advanced.
+ available.value = 0;
+ }
+ return available.value;
+ } catch (ErrnoException errnoException) {
+ if (errnoException.errno == ENOTTY) {
+ // The fd is unwilling to opine about its read buffer.
+ return 0;
+ }
+ throw errnoException.rethrowAsIOException();
+ }
+ }
+
+
+ public static void bind(FileDescriptor fd, InetAddress address, int port) throws SocketException {
+ if (address instanceof Inet6Address && ((Inet6Address) address).getScopeId() == 0) {
+ // Linux won't let you bind a link-local address without a scope id. Find one.
+ NetworkInterface nif = NetworkInterface.getByInetAddress(address);
+ if (nif == null) {
+ throw new SocketException("Can't bind to a link-local address without a scope id: " + address);
+ }
+ try {
+ address = Inet6Address.getByAddress(address.getHostName(), address.getAddress(), nif.getIndex());
+ } catch (UnknownHostException ex) {
+ throw new AssertionError(ex); // Can't happen.
+ }
+ }
+ try {
+ Libcore.os.bind(fd, address, port);
+ } catch (ErrnoException errnoException) {
+ throw new BindException(errnoException.getMessage(), errnoException);
+ }
+ }
+
+
+ /**
+ * Connects socket 'fd' to 'inetAddress' on 'port', with no timeout. The lack of a timeout
+ * means this method won't throw SocketTimeoutException.
+ */
+ public static boolean connect(FileDescriptor fd, InetAddress inetAddress, int port) throws SocketException {
+ try {
+ return IoBridge.connect(fd, inetAddress, port, 0);
+ } catch (SocketTimeoutException ex) {
+ throw new AssertionError(ex); // Can't happen for a connect without a timeout.
+ }
+ }
+
+ /**
+ * Connects socket 'fd' to 'inetAddress' on 'port', with a the given 'timeoutMs'.
+ * Use timeoutMs == 0 for a blocking connect with no timeout.
+ */
+ 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), errnoException);
+ } catch (SocketException ex) {
+ throw ex; // We don't want to doubly wrap these.
+ } catch (SocketTimeoutException ex) {
+ throw ex; // We don't want to doubly wrap these.
+ } catch (IOException ex) {
+ throw new SocketException(ex);
+ }
+ }
+
+ 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) {
+ Libcore.os.connect(fd, inetAddress, port);
+ return true;
+ }
+
+ // With a timeout, we set the socket to non-blocking, connect(2), and then loop
+ // using poll(2) to decide whether we're connected, whether we should keep waiting,
+ // or whether we've seen a permanent failure and should give up.
+ long finishTimeMs = System.currentTimeMillis() + timeoutMs;
+ IoUtils.setBlocking(fd, false);
+ try {
+ 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) {
+ throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));
+ }
+ } while (!IoBridge.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs));
+ return true; // Or we'd have thrown.
+ } finally {
+ IoUtils.setBlocking(fd, true);
+ }
+ }
+
+ private static String connectDetail(InetAddress inetAddress, int port, int timeoutMs, ErrnoException cause) {
+ String detail = "failed to connect to " + inetAddress + " (port " + port + ")";
+ if (timeoutMs > 0) {
+ detail += " after " + timeoutMs + "ms";
+ }
+ if (cause != null) {
+ detail += ": " + cause.getMessage();
+ }
+ return detail;
+ }
+
+ public static void closeSocket(FileDescriptor fd) throws IOException {
+ if (!fd.valid()) {
+ // Socket.close doesn't throw if you try to close an already-closed socket.
+ return;
+ }
+ int intFd = fd.getInt$();
+ fd.setInt$(-1);
+ FileDescriptor oldFd = new FileDescriptor();
+ oldFd.setInt$(intFd);
+ AsynchronousCloseMonitor.signalBlockedThreads(oldFd);
+ try {
+ Libcore.os.close(oldFd);
+ } catch (ErrnoException errnoException) {
+ // TODO: are there any cases in which we should throw?
+ }
+ }
+
+ public static boolean isConnected(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs, int remainingTimeoutMs) throws IOException {
+ ErrnoException cause = null;
+ try {
+ StructPollfd[] pollFds = new StructPollfd[] { new StructPollfd() };
+ pollFds[0].fd = fd;
+ pollFds[0].events = (short) POLLOUT;
+ int rc = Libcore.os.poll(pollFds, remainingTimeoutMs);
+ if (rc == 0) {
+ return false; // Timeout.
+ }
+ int connectError = Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_ERROR);
+ if (connectError == 0) {
+ return true; // Success!
+ }
+ throw new ErrnoException("isConnected", connectError); // The connect(2) failed.
+ } catch (ErrnoException errnoException) {
+ if (errnoException.errno == EINTR) {
+ return false; // Punt and ask the caller to try again.
+ } else {
+ cause = errnoException;
+ }
+ }
+ // TODO: is it really helpful/necessary to throw so many different exceptions?
+ String detail = connectDetail(inetAddress, port, timeoutMs, cause);
+ if (cause.errno == ECONNRESET || cause.errno == ECONNREFUSED ||
+ cause.errno == EADDRNOTAVAIL || cause.errno == EADDRINUSE ||
+ cause.errno == ENETUNREACH) {
+ throw new ConnectException(detail, cause);
+ } else if (cause.errno == EACCES) {
+ throw new SecurityException(detail, cause);
+ } else if (cause.errno == ETIMEDOUT) {
+ throw new SocketTimeoutException(detail, cause);
+ }
+ throw new SocketException(detail, cause);
+ }
+
+ // Socket options used by java.net but not exposed in SocketOptions.
+ public static final int JAVA_MCAST_JOIN_GROUP = 19;
+ public static final int JAVA_MCAST_LEAVE_GROUP = 20;
+ public static final int JAVA_IP_MULTICAST_TTL = 17;
+
+ /**
+ * java.net has its own socket options similar to the underlying Unix ones. We paper over the
+ * differences here.
+ */
+ public static Object getSocketOption(FileDescriptor fd, int option) throws SocketException {
+ try {
+ return getSocketOptionErrno(fd, option);
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsSocketException();
+ }
+ }
+
+ private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws SocketException {
+ switch (option) {
+ case SocketOptions.IP_MULTICAST_IF:
+ // This is IPv4-only.
+ return Libcore.os.getsockoptInAddr(fd, IPPROTO_IP, IP_MULTICAST_IF);
+ case SocketOptions.IP_MULTICAST_IF2:
+ // This is IPv6-only.
+ return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF);
+ case SocketOptions.IP_MULTICAST_LOOP:
+ // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
+ // it doesn't matter which we return.
+ return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP));
+ case IoBridge.JAVA_IP_MULTICAST_TTL:
+ // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
+ // it doesn't matter which we return.
+ return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
+ case SocketOptions.IP_TOS:
+ // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
+ // it doesn't matter which we return.
+ return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS);
+ case SocketOptions.SO_BROADCAST:
+ return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_BROADCAST));
+ case SocketOptions.SO_KEEPALIVE:
+ return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE));
+ case SocketOptions.SO_LINGER:
+ StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER);
+ if (!linger.isOn()) {
+ return false;
+ }
+ return linger.l_linger;
+ case SocketOptions.SO_OOBINLINE:
+ return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE));
+ case SocketOptions.SO_RCVBUF:
+ return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF);
+ case SocketOptions.SO_REUSEADDR:
+ return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR));
+ case SocketOptions.SO_SNDBUF:
+ return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF);
+ case SocketOptions.SO_TIMEOUT:
+ return (int) Libcore.os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO).toMillis();
+ case SocketOptions.TCP_NODELAY:
+ return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY));
+ default:
+ throw new SocketException("Unknown socket option: " + option);
+ }
+ }
+
+ private static boolean booleanFromInt(int i) {
+ return (i != 0);
+ }
+
+ private static int booleanToInt(boolean b) {
+ return b ? 1 : 0;
+ }
+
+ /**
+ * java.net has its own socket options similar to the underlying Unix ones. We paper over the
+ * differences here.
+ */
+ public static void setSocketOption(FileDescriptor fd, int option, Object value) throws SocketException {
+ try {
+ setSocketOptionErrno(fd, option, value);
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsSocketException();
+ }
+ }
+
+ private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws SocketException {
+ switch (option) {
+ case SocketOptions.IP_MULTICAST_IF:
+ throw new UnsupportedOperationException("Use IP_MULTICAST_IF2 on Android");
+ case SocketOptions.IP_MULTICAST_IF2:
+ // Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int.
+ Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, (Integer) value);
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (Integer) value);
+ return;
+ case SocketOptions.IP_MULTICAST_LOOP:
+ // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
+ Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, booleanToInt((Boolean) value));
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, booleanToInt((Boolean) value));
+ return;
+ case IoBridge.JAVA_IP_MULTICAST_TTL:
+ // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
+ // IPv4 multicast TTL uses a byte.
+ Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_TTL, (Integer) value);
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (Integer) value);
+ return;
+ case SocketOptions.IP_TOS:
+ Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_TOS, (Integer) value);
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS, (Integer) value);
+ return;
+ case SocketOptions.SO_BROADCAST:
+ Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_BROADCAST, booleanToInt((Boolean) value));
+ return;
+ case SocketOptions.SO_KEEPALIVE:
+ Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE, booleanToInt((Boolean) value));
+ return;
+ case SocketOptions.SO_LINGER:
+ boolean on = false;
+ int seconds = 0;
+ if (value instanceof Integer) {
+ on = true;
+ seconds = Math.min((Integer) value, 65535);
+ }
+ StructLinger linger = new StructLinger(booleanToInt(on), seconds);
+ Libcore.os.setsockoptLinger(fd, SOL_SOCKET, SO_LINGER, linger);
+ return;
+ case SocketOptions.SO_OOBINLINE:
+ Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE, booleanToInt((Boolean) value));
+ return;
+ case SocketOptions.SO_RCVBUF:
+ Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, (Integer) value);
+ return;
+ case SocketOptions.SO_REUSEADDR:
+ Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR, booleanToInt((Boolean) value));
+ return;
+ case SocketOptions.SO_SNDBUF:
+ Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_SNDBUF, (Integer) value);
+ return;
+ case SocketOptions.SO_TIMEOUT:
+ int millis = (Integer) value;
+ StructTimeval tv = StructTimeval.fromMillis(millis);
+ Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv);
+ return;
+ case SocketOptions.TCP_NODELAY:
+ Libcore.os.setsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY, booleanToInt((Boolean) value));
+ return;
+ case IoBridge.JAVA_MCAST_JOIN_GROUP:
+ case IoBridge.JAVA_MCAST_LEAVE_GROUP:
+ StructGroupReq groupReq = (StructGroupReq) value;
+ int level = (groupReq.gr_group instanceof Inet4Address) ? IPPROTO_IP : IPPROTO_IPV6;
+ int op = (option == JAVA_MCAST_JOIN_GROUP) ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP;
+ Libcore.os.setsockoptGroupReq(fd, level, op, groupReq);
+ return;
+ default:
+ throw new SocketException("Unknown socket option: " + option);
+ }
+ }
+
+ /**
+ * java.io only throws FileNotFoundException when opening files, regardless of what actually
+ * went wrong. Additionally, java.io is more restrictive than POSIX when it comes to opening
+ * directories: POSIX says read-only is okay, but java.io doesn't even allow that. We also
+ * have an Android-specific hack to alter the default permissions.
+ */
+ public static FileDescriptor open(String path, int flags) throws FileNotFoundException {
+ FileDescriptor fd = null;
+ try {
+ // On Android, we don't want default permissions to allow global access.
+ int mode = ((flags & O_ACCMODE) == O_RDONLY) ? 0 : 0600;
+ fd = Libcore.os.open(path, flags, mode);
+ if (fd.valid()) {
+ // Posix open(2) fails with EISDIR only if you ask for write permission.
+ // Java disallows reading directories too.
+ boolean isDirectory = false;
+ if (S_ISDIR(Libcore.os.fstat(fd).st_mode)) {
+ throw new ErrnoException("open", EISDIR);
+ }
+ }
+ return fd;
+ } catch (ErrnoException errnoException) {
+ try {
+ if (fd != null) {
+ IoUtils.close(fd);
+ }
+ } catch (IOException ignored) {
+ }
+ FileNotFoundException ex = new FileNotFoundException(path + ": " + errnoException.getMessage());
+ ex.initCause(errnoException);
+ throw ex;
+ }
+ }
+
+ /**
+ * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional
+ * Unix practice where you'd read until you got 0 bytes (and any future read would return -1).
+ */
+ public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
+ Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
+ if (byteCount == 0) {
+ return 0;
+ }
+ try {
+ int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount);
+ if (readCount == 0) {
+ return -1;
+ }
+ return readCount;
+ } catch (ErrnoException errnoException) {
+ if (errnoException.errno == EAGAIN) {
+ // We return 0 rather than throw if we try to read from an empty non-blocking pipe.
+ return 0;
+ }
+ throw errnoException.rethrowAsIOException();
+ }
+ }
+
+ /**
+ * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike
+ * Unix it never just writes as many bytes as happens to be convenient.)
+ */
+ public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
+ Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
+ if (byteCount == 0) {
+ return;
+ }
+ try {
+ while (byteCount > 0) {
+ int bytesWritten = Libcore.os.write(fd, bytes, byteOffset, byteCount);
+ byteCount -= bytesWritten;
+ byteOffset += bytesWritten;
+ }
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsIOException();
+ }
+ }
+
+ public static int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws IOException {
+ boolean isDatagram = (inetAddress != null);
+ if (!isDatagram && byteCount <= 0) {
+ return 0;
+ }
+ int result;
+ try {
+ result = Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
+ } catch (ErrnoException errnoException) {
+ result = maybeThrowAfterSendto(isDatagram, errnoException);
+ }
+ return result;
+ }
+
+ public static int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws IOException {
+ boolean isDatagram = (inetAddress != null);
+ if (!isDatagram && buffer.remaining() == 0) {
+ return 0;
+ }
+ int result;
+ try {
+ result = Libcore.os.sendto(fd, buffer, flags, inetAddress, port);
+ } catch (ErrnoException errnoException) {
+ result = maybeThrowAfterSendto(isDatagram, errnoException);
+ }
+ return result;
+ }
+
+ private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException) throws SocketException {
+ if (isDatagram) {
+ if (errnoException.errno == ECONNRESET || errnoException.errno == ECONNREFUSED) {
+ return 0;
+ }
+ } else {
+ if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
+ // We were asked to write to a non-blocking socket, but were told
+ // it would block, so report "no bytes written".
+ return 0;
+ }
+ }
+ throw errnoException.rethrowAsSocketException();
+ }
+
+ public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
+ int result;
+ try {
+ InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
+ result = Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress);
+ result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
+ } catch (ErrnoException errnoException) {
+ result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
+ }
+ return result;
+ }
+
+ public static int recvfrom(boolean isRead, FileDescriptor fd, ByteBuffer buffer, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
+ int result;
+ try {
+ InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
+ result = Libcore.os.recvfrom(fd, buffer, flags, srcAddress);
+ result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
+ } catch (ErrnoException errnoException) {
+ result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
+ }
+ return result;
+ }
+
+ private static int postRecvfrom(boolean isRead, DatagramPacket packet, boolean isConnected, InetSocketAddress srcAddress, int byteCount) {
+ if (isRead && byteCount == 0) {
+ return -1;
+ }
+ if (packet != null) {
+ packet.setLength(byteCount);
+ if (!isConnected) {
+ packet.setAddress(srcAddress.getAddress());
+ packet.setPort(srcAddress.getPort());
+ }
+ }
+ return byteCount;
+ }
+
+ private static int maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected, ErrnoException errnoException) throws SocketException, SocketTimeoutException {
+ if (isRead) {
+ if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
+ return 0;
+ } else {
+ throw errnoException.rethrowAsSocketException();
+ }
+ } else {
+ if (isConnected && errnoException.errno == ECONNREFUSED) {
+ throw new PortUnreachableException("", errnoException);
+ } else if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
+ throw new SocketTimeoutException(errnoException);
+ } else {
+ throw errnoException.rethrowAsSocketException();
+ }
+ }
+ }
+
+ public static FileDescriptor socket(boolean stream) throws SocketException {
+ FileDescriptor fd;
+ try {
+ fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
+
+ // The RFC (http://www.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults
+ // to 1. The Linux kernel (at least up to 2.6.38) accidentally defaults to 64 (which
+ // would be correct for the *unicast* hop limit).
+ // See http://www.spinics.net/lists/netdev/msg129022.html, though no patch appears to
+ // have been applied as a result of that discussion. If that bug is ever fixed, we can
+ // remove this code. Until then, we manually set the hop limit on IPv6 datagram sockets.
+ // (IPv4 is already correct.)
+ if (!stream) {
+ Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1);
+ }
+
+ return fd;
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsSocketException();
+ }
+ }
+
+ public static InetAddress getSocketLocalAddress(FileDescriptor fd) {
+ SocketAddress sa = Libcore.os.getsockname(fd);
+ InetSocketAddress isa = (InetSocketAddress) sa;
+ return isa.getAddress();
+ }
+
+ public static int getSocketLocalPort(FileDescriptor fd) {
+ SocketAddress sa = Libcore.os.getsockname(fd);
+ InetSocketAddress isa = (InetSocketAddress) sa;
+ return isa.getPort();
+ }
+
+}
diff --git a/luni/src/main/java/libcore/io/IoUtils.java b/luni/src/main/java/libcore/io/IoUtils.java
index 4a9772e..6680882 100644
--- a/luni/src/main/java/libcore/io/IoUtils.java
+++ b/luni/src/main/java/libcore/io/IoUtils.java
@@ -19,28 +19,10 @@
import java.io.Closeable;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
-import java.net.BindException;
-import java.net.ConnectException;
-import java.net.DatagramPacket;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.NetworkInterface;
-import java.net.PortUnreachableException;
import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.net.SocketOptions;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
import java.nio.charset.Charsets;
-import java.util.Arrays;
-import libcore.util.MutableInt;
import static libcore.io.OsConstants.*;
public final class IoUtils {
@@ -48,229 +30,6 @@
}
/**
- * Implements java.io/java.net "available" semantics.
- */
- public static int available(FileDescriptor fd) throws IOException {
- try {
- MutableInt available = new MutableInt(0);
- int rc = Libcore.os.ioctlInt(fd, FIONREAD, available);
- if (available.value < 0) {
- // If the fd refers to a regular file, the result is the difference between
- // the file size and the file position. This may be negative if the position
- // is past the end of the file. If the fd refers to a special file masquerading
- // as a regular file, the result may be negative because the special file
- // may appear to have zero size and yet a previous read call may have
- // read some amount of data and caused the file position to be advanced.
- available.value = 0;
- }
- return available.value;
- } catch (ErrnoException errnoException) {
- if (errnoException.errno == ENOTTY) {
- // The fd is unwilling to opine about its read buffer.
- return 0;
- }
- throw errnoException.rethrowAsIOException();
- }
- }
-
- /**
- * java.io only throws FileNotFoundException when opening files, regardless of what actually
- * went wrong. Additionally, java.io is more restrictive than POSIX when it comes to opening
- * directories: POSIX says read-only is okay, but java.io doesn't even allow that. We also
- * have an Android-specific hack to alter the default permissions.
- */
- public static FileDescriptor open(String path, int flags) throws FileNotFoundException {
- FileDescriptor fd = null;
- try {
- // On Android, we don't want default permissions to allow global access.
- int mode = ((flags & O_ACCMODE) == O_RDONLY) ? 0 : 0600;
- fd = Libcore.os.open(path, flags, mode);
- if (fd.valid()) {
- // Posix open(2) fails with EISDIR only if you ask for write permission.
- // Java disallows reading directories too.
- boolean isDirectory = false;
- if (S_ISDIR(Libcore.os.fstat(fd).st_mode)) {
- throw new ErrnoException("open", EISDIR);
- }
- }
- return fd;
- } catch (ErrnoException errnoException) {
- try {
- if (fd != null) {
- close(fd);
- }
- } catch (IOException ignored) {
- }
- FileNotFoundException ex = new FileNotFoundException(path + ": " + errnoException.getMessage());
- ex.initCause(errnoException);
- throw ex;
- }
- }
-
- /**
- * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional
- * Unix practice where you'd read until you got 0 bytes (and any future read would return -1).
- */
- public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
- Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
- if (byteCount == 0) {
- return 0;
- }
- try {
- int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount);
- if (readCount == 0) {
- return -1;
- }
- return readCount;
- } catch (ErrnoException errnoException) {
- if (errnoException.errno == EAGAIN) {
- // We return 0 rather than throw if we try to read from an empty non-blocking pipe.
- return 0;
- }
- throw errnoException.rethrowAsIOException();
- }
- }
-
- /**
- * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike
- * Unix it never just writes as many bytes as happens to be convenient.)
- */
- public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
- Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
- if (byteCount == 0) {
- return;
- }
- try {
- while (byteCount > 0) {
- int bytesWritten = Libcore.os.write(fd, bytes, byteOffset, byteCount);
- byteCount -= bytesWritten;
- byteOffset += bytesWritten;
- }
- } catch (ErrnoException errnoException) {
- throw errnoException.rethrowAsIOException();
- }
- }
-
- public static int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws IOException {
- boolean isDatagram = (inetAddress != null);
- if (!isDatagram && byteCount <= 0) {
- return 0;
- }
- int result;
- try {
- result = Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
- } catch (ErrnoException errnoException) {
- result = maybeThrowAfterSendto(isDatagram, errnoException);
- }
- return result;
- }
-
- public static int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws IOException {
- boolean isDatagram = (inetAddress != null);
- if (!isDatagram && buffer.remaining() == 0) {
- return 0;
- }
- int result;
- try {
- result = Libcore.os.sendto(fd, buffer, flags, inetAddress, port);
- } catch (ErrnoException errnoException) {
- result = maybeThrowAfterSendto(isDatagram, errnoException);
- }
- return result;
- }
-
- private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException) throws SocketException {
- if (isDatagram) {
- if (errnoException.errno == ECONNRESET || errnoException.errno == ECONNREFUSED) {
- return 0;
- }
- } else {
- if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
- // We were asked to write to a non-blocking socket, but were told
- // it would block, so report "no bytes written".
- return 0;
- }
- }
- throw errnoException.rethrowAsSocketException();
- }
-
- public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
- int result;
- try {
- InetSocketAddress isa = (packet != null && !isConnected) ? new InetSocketAddress() : null;
- result = Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, isa);
- result = postRecvfrom(isRead, packet, isConnected, isa, result);
- } catch (ErrnoException errnoException) {
- result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
- }
- return result;
- }
-
- public static int recvfrom(boolean isRead, FileDescriptor fd, ByteBuffer buffer, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
- int result;
- try {
- InetSocketAddress isa = (packet != null && !isConnected) ? new InetSocketAddress() : null;
- result = Libcore.os.recvfrom(fd, buffer, flags, isa);
- result = postRecvfrom(isRead, packet, isConnected, isa, result);
- } catch (ErrnoException errnoException) {
- result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
- }
- return result;
- }
-
- private static int postRecvfrom(boolean isRead, DatagramPacket packet, boolean isConnected, InetSocketAddress isa, int byteCount) {
- if (isRead && byteCount == 0) {
- return -1;
- }
- if (packet != null) {
- packet.setLength(byteCount);
- if (!isConnected) {
- packet.setAddress(isa.getAddress());
- packet.setPort(isa.getPort());
- }
- }
- return byteCount;
- }
-
- private static int maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected, ErrnoException errnoException) throws SocketException, SocketTimeoutException {
- if (isRead) {
- if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
- return 0;
- } else {
- throw errnoException.rethrowAsSocketException();
- }
- } else {
- if (isConnected && errnoException.errno == ECONNREFUSED) {
- throw new PortUnreachableException("", errnoException);
- } else if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
- throw new SocketTimeoutException("", errnoException);
- } else {
- throw errnoException.rethrowAsSocketException();
- }
- }
- }
-
- public static void bind(FileDescriptor fd, InetAddress address, int port) throws SocketException {
- if (address instanceof Inet6Address && ((Inet6Address) address).getScopeId() == 0) {
- // Linux won't let you bind a link-local address without a scope id. Find one.
- NetworkInterface nif = NetworkInterface.getByInetAddress(address);
- if (nif == null) {
- throw new SocketException("Can't bind to a link-local address without a scope id: " + address);
- }
- try {
- address = Inet6Address.getByAddress(address.getHostName(), address.getAddress(), nif.getIndex());
- } catch (UnknownHostException ex) {
- throw new AssertionError(ex); // Can't happen.
- }
- }
- try {
- Libcore.os.bind(fd, address, port);
- } catch (ErrnoException errnoException) {
- throw new BindException(errnoException.getMessage(), errnoException);
- }
- }
-
- /**
* Calls close(2) on 'fd'. Also resets the internal int to -1. Does nothing if 'fd' is null
* or invalid.
*/
@@ -318,135 +77,6 @@
}
}
- public static void closeSocket(FileDescriptor fd) throws IOException {
- if (!fd.valid()) {
- // Socket.close doesn't throw if you try to close an already-closed socket.
- return;
- }
- int intFd = fd.getInt$();
- fd.setInt$(-1);
- FileDescriptor oldFd = new FileDescriptor();
- oldFd.setInt$(intFd);
- AsynchronousCloseMonitor.signalBlockedThreads(oldFd);
- try {
- Libcore.os.close(oldFd);
- } catch (ErrnoException errnoException) {
- // TODO: are there any cases in which we should throw?
- }
- }
-
- /**
- * Connects socket 'fd' to 'inetAddress' on 'port', with no timeout. The lack of a timeout
- * means this method won't throw SocketTimeoutException.
- */
- public static boolean connect(FileDescriptor fd, InetAddress inetAddress, int port) throws SocketException {
- try {
- return IoUtils.connect(fd, inetAddress, port, 0);
- } catch (SocketTimeoutException ex) {
- throw new AssertionError(ex); // Can't happen for a connect without a timeout.
- }
- }
-
- /**
- * Connects socket 'fd' to 'inetAddress' on 'port', with a the given 'timeoutMs'.
- * Use timeoutMs == 0 for a blocking connect with no timeout.
- */
- 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), errnoException);
- } catch (SocketException ex) {
- throw ex; // We don't want to doubly wrap these.
- } catch (SocketTimeoutException ex) {
- throw ex; // We don't want to doubly wrap these.
- } catch (IOException ex) {
- throw new SocketException(ex);
- }
- }
-
- 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) {
- Libcore.os.connect(fd, inetAddress, port);
- return true;
- }
-
- // With a timeout, we set the socket to non-blocking, connect(2), and then loop
- // using poll(2) to decide whether we're connected, whether we should keep waiting,
- // or whether we've seen a permanent failure and should give up.
- long finishTimeMs = System.currentTimeMillis() + timeoutMs;
- IoUtils.setBlocking(fd, false);
- try {
- 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) {
- throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));
- }
- } while (!IoUtils.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs));
- return true; // Or we'd have thrown.
- } finally {
- IoUtils.setBlocking(fd, true);
- }
- }
-
- private static String connectDetail(InetAddress inetAddress, int port, int timeoutMs, ErrnoException cause) {
- String detail = "failed to connect to " + inetAddress + " (port " + port + ")";
- if (timeoutMs > 0) {
- detail += " after " + timeoutMs + "ms";
- }
- if (cause != null) {
- detail += ": " + cause.getMessage();
- }
- return detail;
- }
-
- public static boolean isConnected(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs, int remainingTimeoutMs) throws IOException {
- ErrnoException cause = null;
- try {
- StructPollfd[] pollFds = new StructPollfd[] { new StructPollfd() };
- pollFds[0].fd = fd;
- pollFds[0].events = (short) POLLOUT;
- int rc = Libcore.os.poll(pollFds, remainingTimeoutMs);
- if (rc == 0) {
- return false; // Timeout.
- }
- int connectError = Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_ERROR);
- if (connectError == 0) {
- return true; // Success!
- }
- throw new ErrnoException("isConnected", connectError); // The connect(2) failed.
- } catch (ErrnoException errnoException) {
- if (errnoException.errno == EINTR) {
- return false; // Punt and ask the caller to try again.
- } else {
- cause = errnoException;
- }
- }
- // TODO: is it really helpful/necessary to throw so many different exceptions?
- String detail = connectDetail(inetAddress, port, timeoutMs, cause);
- if (cause.errno == ECONNRESET || cause.errno == ECONNREFUSED ||
- cause.errno == EADDRNOTAVAIL || cause.errno == EADDRINUSE ||
- cause.errno == ENETUNREACH) {
- throw new ConnectException(detail, cause);
- } else if (cause.errno == EACCES) {
- throw new SecurityException(detail, cause);
- } else if (cause.errno == ETIMEDOUT) {
- throw new SocketTimeoutException(detail, cause);
- }
- throw new SocketException(detail, cause);
- }
-
/**
* Sets 'fd' to be blocking or non-blocking, according to the state of 'blocking'.
*/
@@ -464,196 +94,6 @@
}
}
- public static FileDescriptor socket(boolean stream) throws SocketException {
- FileDescriptor fd;
- try {
- fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
-
- // The RFC (http://www.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults
- // to 1. The Linux kernel (at least up to 2.6.38) accidentally defaults to 64 (which
- // would be correct for the *unicast* hop limit).
- // See http://www.spinics.net/lists/netdev/msg129022.html, though no patch appears to
- // have been applied as a result of that discussion. If that bug is ever fixed, we can
- // remove this code. Until then, we manually set the hop limit on IPv6 datagram sockets.
- // (IPv4 is already correct.)
- if (!stream) {
- Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1);
- }
-
- return fd;
- } catch (ErrnoException errnoException) {
- throw errnoException.rethrowAsSocketException();
- }
- }
-
- // Socket options used by java.net but not exposed in SocketOptions.
- public static final int JAVA_MCAST_JOIN_GROUP = 19;
- public static final int JAVA_MCAST_LEAVE_GROUP = 20;
- public static final int JAVA_IP_MULTICAST_TTL = 17;
-
- /**
- * java.net has its own socket options similar to the underlying Unix ones. We paper over the
- * differences here.
- */
- public static Object getSocketOption(FileDescriptor fd, int option) throws SocketException {
- try {
- return getSocketOptionErrno(fd, option);
- } catch (ErrnoException errnoException) {
- throw errnoException.rethrowAsSocketException();
- }
- }
-
- private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws SocketException {
- switch (option) {
- case SocketOptions.IP_MULTICAST_IF:
- // This is IPv4-only.
- return Libcore.os.getsockoptInAddr(fd, IPPROTO_IP, IP_MULTICAST_IF);
- case SocketOptions.IP_MULTICAST_IF2:
- // This is IPv6-only.
- return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF);
- case SocketOptions.IP_MULTICAST_LOOP:
- // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
- // it doesn't matter which we return.
- return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP));
- case IoUtils.JAVA_IP_MULTICAST_TTL:
- // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
- // it doesn't matter which we return.
- return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
- case SocketOptions.IP_TOS:
- // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
- // it doesn't matter which we return.
- return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS);
- case SocketOptions.SO_BROADCAST:
- return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_BROADCAST));
- case SocketOptions.SO_KEEPALIVE:
- return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE));
- case SocketOptions.SO_LINGER:
- StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER);
- if (!linger.isOn()) {
- return false;
- }
- return linger.l_linger;
- case SocketOptions.SO_OOBINLINE:
- return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE));
- case SocketOptions.SO_RCVBUF:
- return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF);
- case SocketOptions.SO_REUSEADDR:
- return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR));
- case SocketOptions.SO_SNDBUF:
- return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF);
- case SocketOptions.SO_TIMEOUT:
- return (int) Libcore.os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO).toMillis();
- case SocketOptions.TCP_NODELAY:
- return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY));
- default:
- throw new SocketException("Unknown socket option: " + option);
- }
- }
-
- private static boolean booleanFromInt(int i) {
- return (i != 0);
- }
-
- private static int booleanToInt(boolean b) {
- return b ? 1 : 0;
- }
-
- /**
- * java.net has its own socket options similar to the underlying Unix ones. We paper over the
- * differences here.
- */
- public static void setSocketOption(FileDescriptor fd, int option, Object value) throws SocketException {
- try {
- setSocketOptionErrno(fd, option, value);
- } catch (ErrnoException errnoException) {
- throw errnoException.rethrowAsSocketException();
- }
- }
-
- private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws SocketException {
- switch (option) {
- case SocketOptions.IP_MULTICAST_IF:
- throw new UnsupportedOperationException("Use IP_MULTICAST_IF2 on Android");
- case SocketOptions.IP_MULTICAST_IF2:
- // Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int.
- Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, (Integer) value);
- Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (Integer) value);
- return;
- case SocketOptions.IP_MULTICAST_LOOP:
- // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
- Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, booleanToInt((Boolean) value));
- Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, booleanToInt((Boolean) value));
- return;
- case IoUtils.JAVA_IP_MULTICAST_TTL:
- // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
- // IPv4 multicast TTL uses a byte.
- Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_TTL, (Integer) value);
- Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (Integer) value);
- return;
- case SocketOptions.IP_TOS:
- Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_TOS, (Integer) value);
- Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS, (Integer) value);
- return;
- case SocketOptions.SO_BROADCAST:
- Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_BROADCAST, booleanToInt((Boolean) value));
- return;
- case SocketOptions.SO_KEEPALIVE:
- Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE, booleanToInt((Boolean) value));
- return;
- case SocketOptions.SO_LINGER:
- boolean on = false;
- int seconds = 0;
- if (value instanceof Integer) {
- on = true;
- seconds = Math.min((Integer) value, 65535);
- }
- StructLinger linger = new StructLinger(booleanToInt(on), seconds);
- Libcore.os.setsockoptLinger(fd, SOL_SOCKET, SO_LINGER, linger);
- return;
- case SocketOptions.SO_OOBINLINE:
- Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE, booleanToInt((Boolean) value));
- return;
- case SocketOptions.SO_RCVBUF:
- Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, (Integer) value);
- return;
- case SocketOptions.SO_REUSEADDR:
- Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR, booleanToInt((Boolean) value));
- return;
- case SocketOptions.SO_SNDBUF:
- Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_SNDBUF, (Integer) value);
- return;
- case SocketOptions.SO_TIMEOUT:
- int millis = (Integer) value;
- StructTimeval tv = StructTimeval.fromMillis(millis);
- Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv);
- return;
- case SocketOptions.TCP_NODELAY:
- Libcore.os.setsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY, booleanToInt((Boolean) value));
- return;
- case IoUtils.JAVA_MCAST_JOIN_GROUP:
- case IoUtils.JAVA_MCAST_LEAVE_GROUP:
- StructGroupReq groupReq = (StructGroupReq) value;
- int level = (groupReq.gr_group instanceof Inet4Address) ? IPPROTO_IP : IPPROTO_IPV6;
- int op = (option == JAVA_MCAST_JOIN_GROUP) ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP;
- Libcore.os.setsockoptGroupReq(fd, level, op, groupReq);
- return;
- default:
- throw new SocketException("Unknown socket option: " + option);
- }
- }
-
- public static InetAddress getSocketLocalAddress(FileDescriptor fd) {
- SocketAddress sa = Libcore.os.getsockname(fd);
- InetSocketAddress isa = (InetSocketAddress) sa;
- return isa.getAddress();
- }
-
- public static int getSocketLocalPort(FileDescriptor fd) {
- SocketAddress sa = Libcore.os.getsockname(fd);
- InetSocketAddress isa = (InetSocketAddress) sa;
- return isa.getPort();
- }
-
/**
* Returns the contents of 'path' as a byte array.
*/
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index e44cfb9..bd50998 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -25,6 +25,7 @@
import libcore.util.MutableLong;
public interface Os {
+ public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException;
public boolean access(String path, int mode) throws ErrnoException;
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
public void chmod(String path, int mode) throws ErrnoException;
@@ -83,8 +84,8 @@
public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException;
public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException;
public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException;
- public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress inetSocketAddress) throws ErrnoException;
- public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress inetSocketAddress) throws ErrnoException;
+ public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException;
+ public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException;
public void remove(String path) throws ErrnoException;
public void rename(String oldPath, String newPath) throws ErrnoException;
public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException;
@@ -110,6 +111,7 @@
public void symlink(String oldPath, String newPath) throws ErrnoException;
public long sysconf(int name);
public StructUtsname uname() throws ErrnoException;
+ public int waitpid(int pid, MutableInt status, int options) throws ErrnoException;
public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException;
public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException;
public int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index 2f52d752..f976209 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -28,6 +28,7 @@
public final class Posix implements Os {
Posix() { }
+ public native FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException;
public native boolean access(String path, int mode) throws ErrnoException;
public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
public native void chmod(String path, int mode) throws ErrnoException;
@@ -94,18 +95,18 @@
}
private native int readBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException;
public native int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException;
- public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress inetSocketAddress) throws ErrnoException {
+ public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException {
if (buffer.isDirect()) {
- return recvfromBytes(fd, buffer, buffer.position(), buffer.remaining(), flags, inetSocketAddress);
+ return recvfromBytes(fd, buffer, buffer.position(), buffer.remaining(), flags, srcAddress);
} else {
- return recvfromBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining(), flags, inetSocketAddress);
+ return recvfromBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining(), flags, srcAddress);
}
}
- public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress inetSocketAddress) throws ErrnoException {
+ public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException {
// This indirection isn't strictly necessary, but ensures that our public interface is type safe.
- return recvfromBytes(fd, bytes, byteOffset, byteCount, flags, inetSocketAddress);
+ return recvfromBytes(fd, bytes, byteOffset, byteCount, flags, srcAddress);
}
- private native int recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress inetSocketAddress) throws ErrnoException;
+ private native int recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException;
public native void remove(String path) throws ErrnoException;
public native void rename(String oldPath, String newPath) throws ErrnoException;
public native long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException;
@@ -140,6 +141,7 @@
public native void symlink(String oldPath, String newPath) throws ErrnoException;
public native long sysconf(int name);
public native StructUtsname uname() throws ErrnoException;
+ public native int waitpid(int pid, MutableInt status, int options) throws ErrnoException;
public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {
if (buffer.isDirect()) {
return writeBytes(fd, buffer, buffer.position(), buffer.remaining());
diff --git a/luni/src/main/java/libcore/net/RawSocket.java b/luni/src/main/java/libcore/net/RawSocket.java
index 2907964..bb29fb0 100644
--- a/luni/src/main/java/libcore/net/RawSocket.java
+++ b/luni/src/main/java/libcore/net/RawSocket.java
@@ -22,7 +22,7 @@
import java.io.IOException;
import java.net.SocketException;
import java.util.Arrays;
-import libcore.io.IoUtils;
+import libcore.io.IoBridge;
/**
* This class allows raw L2 packets to be sent and received via the
@@ -111,7 +111,7 @@
*/
public void close() throws IOException {
guard.close();
- IoUtils.closeSocket(fd);
+ IoBridge.closeSocket(fd);
}
@Override protected void finalize() throws Throwable {
diff --git a/luni/src/main/java/libcore/net/http/HttpEngine.java b/luni/src/main/java/libcore/net/http/HttpEngine.java
index 01090f1..d95e21c 100644
--- a/luni/src/main/java/libcore/net/http/HttpEngine.java
+++ b/luni/src/main/java/libcore/net/http/HttpEngine.java
@@ -789,9 +789,9 @@
if (responseCache instanceof HttpResponseCache) {
((HttpResponseCache) responseCache).trackConditionalCacheHit();
}
- // discard the network response and use the cache response
+ // Discard the network response body. Combine the headers.
release(true);
- setResponse(cachedResponseHeaders, cachedResponseBody);
+ setResponse(cachedResponseHeaders.combine(responseHeaders), cachedResponseBody);
return;
} else {
IoUtils.closeQuietly(cachedResponseBody);
diff --git a/luni/src/main/java/libcore/net/http/RawHeaders.java b/luni/src/main/java/libcore/net/http/RawHeaders.java
index be39ef4..75a1392a 100644
--- a/luni/src/main/java/libcore/net/http/RawHeaders.java
+++ b/luni/src/main/java/libcore/net/http/RawHeaders.java
@@ -42,9 +42,9 @@
* <p>This class trims whitespace from values. It never returns values with
* leading or trailing whitespace.
*/
-final class RawHeaders implements Cloneable {
-
+final class RawHeaders {
private static final Comparator<String> FIELD_NAME_COMPARATOR = new Comparator<String>() {
+ @FindBugsSuppressWarnings("ES_COMPARING_PARAMETER_STRING_WITH_EQ")
@Override public int compare(String a, String b) {
if (a == b) {
return 0;
diff --git a/luni/src/main/java/libcore/net/http/RequestHeaders.java b/luni/src/main/java/libcore/net/http/RequestHeaders.java
index 9f7f763..b143f81 100644
--- a/luni/src/main/java/libcore/net/http/RequestHeaders.java
+++ b/luni/src/main/java/libcore/net/http/RequestHeaders.java
@@ -42,7 +42,6 @@
* header is set.
*/
boolean onlyIfCached;
- String noCacheField;
/**
* True if the request contains an authorization field. Although this isn't
@@ -70,7 +69,6 @@
@Override public void handle(String directive, String parameter) {
if (directive.equalsIgnoreCase("no-cache")) {
noCache = true;
- noCacheField = parameter;
} else if (directive.equalsIgnoreCase("max-age")) {
maxAgeSeconds = HeaderParser.parseSeconds(parameter);
} else if (directive.equalsIgnoreCase("max-stale")) {
diff --git a/luni/src/main/java/libcore/net/http/ResponseHeaders.java b/luni/src/main/java/libcore/net/http/ResponseHeaders.java
index a1b4fc4..0764a53 100644
--- a/luni/src/main/java/libcore/net/http/ResponseHeaders.java
+++ b/luni/src/main/java/libcore/net/http/ResponseHeaders.java
@@ -97,7 +97,6 @@
* not permitted if this header is set.
*/
boolean isPublic;
- String privateField;
boolean mustRevalidate;
String etag;
int ageSeconds = -1;
@@ -128,8 +127,6 @@
sMaxAgeSeconds = HeaderParser.parseSeconds(parameter);
} else if (directive.equalsIgnoreCase("public")) {
isPublic = true;
- } else if (directive.equalsIgnoreCase("private")) {
- privateField = parameter;
} else if (directive.equalsIgnoreCase("must-revalidate")) {
mustRevalidate = true;
}
@@ -400,4 +397,47 @@
return false;
}
+
+ /**
+ * Combines this cached header with a network header as defined by RFC 2616,
+ * 13.5.3.
+ */
+ public ResponseHeaders combine(ResponseHeaders network) {
+ RawHeaders result = new RawHeaders();
+
+ for (int i = 0; i < headers.length(); i++) {
+ String fieldName = headers.getFieldName(i);
+ String value = headers.getValue(i);
+ if (fieldName.equals("Warning") && value.startsWith("1")) {
+ continue; // drop 100-level freshness warnings
+ }
+ if (!isEndToEnd(fieldName) || network.headers.get(fieldName) == null) {
+ result.add(fieldName, value);
+ }
+ }
+
+ for (int i = 0; i < network.headers.length(); i++) {
+ String fieldName = network.headers.getFieldName(i);
+ if (isEndToEnd(fieldName)) {
+ result.add(fieldName, network.headers.getValue(i));
+ }
+ }
+
+ return new ResponseHeaders(uri, result);
+ }
+
+ /**
+ * Returns true if {@code fieldName} is an end-to-end HTTP header, as
+ * defined by RFC 2616, 13.5.1.
+ */
+ private static boolean isEndToEnd(String fieldName) {
+ return !fieldName.equalsIgnoreCase("Connection")
+ && !fieldName.equalsIgnoreCase("Keep-Alive")
+ && !fieldName.equalsIgnoreCase("Proxy-Authenticate")
+ && !fieldName.equalsIgnoreCase("Proxy-Authorization")
+ && !fieldName.equalsIgnoreCase("TE")
+ && !fieldName.equalsIgnoreCase("Trailers")
+ && !fieldName.equalsIgnoreCase("Transfer-Encoding")
+ && !fieldName.equalsIgnoreCase("Upgrade");
+ }
}
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
deleted file mode 100644
index 1623e2e..0000000
--- a/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.harmony.luni.platform;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.SocketImpl;
-
-/*
- * The interface for network methods.
- */
-public interface INetworkSystem {
- public void accept(FileDescriptor serverFd, SocketImpl newSocket, FileDescriptor clientFd) throws IOException;
-}
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
deleted file mode 100644
index 4db39ff..0000000
--- a/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.harmony.luni.platform;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.SocketImpl;
-
-/**
- * This wraps native code that implements the INetworkSystem interface.
- * Address length was changed from long to int for performance reasons.
- */
-final class OSNetworkSystem implements INetworkSystem {
- private static final OSNetworkSystem singleton = new OSNetworkSystem();
-
- public static OSNetworkSystem getOSNetworkSystem() {
- return singleton;
- }
-
- private OSNetworkSystem() {
- }
-
- public native void accept(FileDescriptor serverFd, SocketImpl newSocket, FileDescriptor clientFd) throws IOException;
-}
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/Platform.java b/luni/src/main/java/org/apache/harmony/luni/platform/Platform.java
deleted file mode 100644
index db79a59..0000000
--- a/luni/src/main/java/org/apache/harmony/luni/platform/Platform.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.harmony.luni.platform;
-
-import dalvik.system.BlockGuard;
-import dalvik.system.VMStack;
-
-/**
- * The Platform class gives access to the low-level underlying capabilities of
- * the operating system.
- *
- * The platform is structured into operations on the process heap memory,
- * network subsystem, and file system through different OS components.
- *
- * OS components are 'dangerous' in that they pass through the calls and
- * arguments to the OS with very little checking, and as such may cause fatal
- * exceptions in the runtime. Access to the OS components is restricted to
- * trusted code running on the system classpath.
- *
- * @see INetworkSystem
- */
-public class Platform {
- // BlockGuard-policy-free threads should have no extra overhead, but for
- // now they do because ThreadLocal lookups will be done on most operations, which
- // should be relatively less than the speed of the operation.
- // TODO: measure & fix if needed.
- public static final INetworkSystem NETWORK =
- new BlockGuard.WrappedNetworkSystem(OSNetworkSystem.getOSNetworkSystem());
-}
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index 402ac7e..a637a73 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -29,6 +29,7 @@
extern int register_java_lang_ProcessManager(JNIEnv* env);
extern int register_java_lang_RealToString(JNIEnv* env);
extern int register_java_lang_StrictMath(JNIEnv* env);
+extern int register_java_lang_StringToReal(JNIEnv* env);
extern int register_java_lang_System(JNIEnv* env);
extern int register_java_math_NativeBN(JNIEnv* env);
extern int register_java_nio_ByteOrder(JNIEnv* env);
@@ -55,8 +56,6 @@
extern int register_libcore_io_Posix(JNIEnv* env);
extern int register_libcore_net_RawSocket(JNIEnv* env);
extern int register_org_apache_harmony_dalvik_NativeTestTarget(JNIEnv* env);
-extern int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env);
-extern int register_org_apache_harmony_luni_util_FloatingPointParser(JNIEnv* env);
extern int register_org_apache_harmony_xml_ExpatParser(JNIEnv* env);
extern int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env);
@@ -75,6 +74,7 @@
register_java_lang_ProcessManager(env) != -1 &&
register_java_lang_RealToString(env) != -1 &&
register_java_lang_StrictMath(env) != -1 &&
+ register_java_lang_StringToReal(env) != -1 &&
register_java_lang_System(env) != -1 &&
register_java_math_NativeBN(env) != -1 &&
register_java_nio_ByteOrder(env) != -1 &&
@@ -101,8 +101,6 @@
register_libcore_io_Posix(env) != -1 &&
register_libcore_net_RawSocket(env) != -1 &&
register_org_apache_harmony_dalvik_NativeTestTarget(env) != -1 &&
- register_org_apache_harmony_luni_platform_OSNetworkSystem(env) != -1 &&
- register_org_apache_harmony_luni_util_FloatingPointParser(env) != -1 &&
register_org_apache_harmony_xml_ExpatParser(env) != -1 &&
register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(env) != -1 &&
true;
diff --git a/luni/src/main/native/java_lang_ProcessManager.cpp b/luni/src/main/native/java_lang_ProcessManager.cpp
index 4d2fe72..3648a8f 100644
--- a/luni/src/main/native/java_lang_ProcessManager.cpp
+++ b/luni/src/main/native/java_lang_ProcessManager.cpp
@@ -18,10 +18,8 @@
#include <sys/resource.h>
#include <sys/types.h>
-#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
-#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
@@ -32,88 +30,6 @@
#include "ScopedLocalRef.h"
#include "utils/Log.h"
-/*
- * These are constants shared with the higher level code in
- * ProcessManager.java.
- */
-#define WAIT_STATUS_UNKNOWN (-1) // unknown child status
-#define WAIT_STATUS_NO_CHILDREN (-2) // no children to wait for
-#define WAIT_STATUS_STRANGE_ERRNO (-3) // observed an undocumented errno
-
-/**
- * Loops indefinitely and calls ProcessManager.onExit() when children exit.
- */
-static void ProcessManager_watchChildren(JNIEnv* env, jclass processManagerClass, jobject processManager) {
- static jmethodID onExitMethod = env->GetMethodID(processManagerClass, "onExit", "(II)V");
- if (onExitMethod == NULL) {
- return;
- }
-
- while (true) {
- // Wait for children in our process group.
- int status;
- pid_t pid = waitpid(0, &status, 0);
-
- if (pid >= 0) {
- // Extract real status.
- if (WIFEXITED(status)) {
- status = WEXITSTATUS(status);
- } else if (WIFSIGNALED(status)) {
- status = WTERMSIG(status);
- } else if (WIFSTOPPED(status)) {
- status = WSTOPSIG(status);
- } else {
- status = WAIT_STATUS_UNKNOWN;
- }
- } else {
- /*
- * The pid should be -1 already, but force it here just in case
- * we somehow end up with some other negative value.
- */
- pid = -1;
-
- switch (errno) {
- case ECHILD: {
- /*
- * Expected errno: There are no children to wait()
- * for. The callback will sleep until it is
- * informed of another child coming to life.
- */
- status = WAIT_STATUS_NO_CHILDREN;
- break;
- }
- case EINTR: {
- /*
- * An unblocked signal came in while waiting; just
- * retry the wait().
- */
- continue;
- }
- default: {
- /*
- * Unexpected errno, so squawk! Note: Per the
- * Linux docs, there are no errnos defined for
- * wait() other than the two that are handled
- * immediately above.
- */
- LOGE("Error %d calling wait(): %s", errno, strerror(errno));
- status = WAIT_STATUS_STRANGE_ERRNO;
- break;
- }
- }
- }
-
- env->CallVoidMethod(processManager, onExitMethod, pid, status);
- if (env->ExceptionOccurred()) {
- /*
- * The callback threw, so break out of the loop and return,
- * letting the exception percolate up.
- */
- break;
- }
- }
-}
-
/** Close all open fds > 2 (i.e. everything but stdin/out/err), != skipFd. */
static void closeNonStandardFds(int skipFd1, int skipFd2) {
// TODO: rather than close all these non-open files, we could look in /proc/self/fd.
@@ -347,7 +263,6 @@
}
static JNINativeMethod methods[] = {
- NATIVE_METHOD(ProcessManager, watchChildren, "(Ljava/lang/ProcessManager;)V"),
NATIVE_METHOD(ProcessManager, exec, "([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Z)I"),
};
int register_java_lang_ProcessManager(JNIEnv* env) {
diff --git a/luni/src/main/native/org_apache_harmony_luni_util_FloatingPointParser.cpp b/luni/src/main/native/java_lang_StringToReal.cpp
similarity index 97%
rename from luni/src/main/native/org_apache_harmony_luni_util_FloatingPointParser.cpp
rename to luni/src/main/native/java_lang_StringToReal.cpp
index 48c0a77..06aa076 100644
--- a/luni/src/main/native/org_apache_harmony_luni_util_FloatingPointParser.cpp
+++ b/luni/src/main/native/java_lang_StringToReal.cpp
@@ -989,7 +989,7 @@
return z;
}
-static jfloat FloatingPointParser_parseFltImpl(JNIEnv* env, jclass, jstring s, jint e) {
+static jfloat StringToReal_parseFltImpl(JNIEnv* env, jclass, jstring s, jint e) {
ScopedUtfChars str(env, s);
if (str.c_str() == NULL) {
return 0.0;
@@ -997,7 +997,7 @@
return createFloat(env, str.c_str(), e);
}
-static jdouble FloatingPointParser_parseDblImpl(JNIEnv* env, jclass, jstring s, jint e) {
+static jdouble StringToReal_parseDblImpl(JNIEnv* env, jclass, jstring s, jint e) {
ScopedUtfChars str(env, s);
if (str.c_str() == NULL) {
return 0.0;
@@ -1006,10 +1006,9 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(FloatingPointParser, parseFltImpl, "(Ljava/lang/String;I)F"),
- NATIVE_METHOD(FloatingPointParser, parseDblImpl, "(Ljava/lang/String;I)D"),
+ NATIVE_METHOD(StringToReal, parseFltImpl, "(Ljava/lang/String;I)F"),
+ NATIVE_METHOD(StringToReal, parseDblImpl, "(Ljava/lang/String;I)D"),
};
-int register_org_apache_harmony_luni_util_FloatingPointParser(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "org/apache/harmony/luni/util/FloatingPointParser",
- gMethods, NELEM(gMethods));
+int register_java_lang_StringToReal(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "java/lang/StringToReal", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 22b440c..5b02862 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -51,6 +51,7 @@
#include <sys/uio.h>
#include <sys/utsname.h>
#include <sys/vfs.h> // Bionic doesn't have <sys/statvfs.h>
+#include <sys/wait.h>
#include <unistd.h>
#define TO_JAVA_STRING(NAME, EXP) \
@@ -298,6 +299,23 @@
return true;
}
+static bool fillInetSocketAddress(JNIEnv* env, jint rc, jobject javaInetSocketAddress, const sockaddr_storage* ss) {
+ if (rc == -1 || javaInetSocketAddress == NULL) {
+ return true;
+ }
+ // Fill out the passed-in InetSocketAddress with the sender's IP address and port number.
+ jint port;
+ jobject sender = sockaddrToInetAddress(env, ss, &port);
+ if (sender == NULL) {
+ return false;
+ }
+ static jfieldID addressFid = env->GetFieldID(JniConstants::inetSocketAddressClass, "addr", "Ljava/net/InetAddress;");
+ static jfieldID portFid = env->GetFieldID(JniConstants::inetSocketAddressClass, "port", "I");
+ env->SetObjectField(javaInetSocketAddress, addressFid, sender);
+ env->SetIntField(javaInetSocketAddress, portFid, port);
+ return true;
+}
+
static jobject doStat(JNIEnv* env, jstring javaPath, bool isLstat) {
ScopedUtfChars path(env, javaPath);
if (path.c_str() == NULL) {
@@ -354,6 +372,21 @@
struct passwd* mResult;
};
+static jobject Posix_accept(JNIEnv* env, jobject, jobject javaFd, jobject javaInetSocketAddress) {
+ sockaddr_storage ss;
+ socklen_t sl = sizeof(ss);
+ memset(&ss, 0, sizeof(ss));
+ int fd;
+ sockaddr* peer = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
+ socklen_t* peerLength = (javaInetSocketAddress != NULL) ? &sl : 0;
+ jint clientFd = NET_FAILURE_RETRY("accept", accept(fd, peer, peerLength));
+ if (clientFd == -1 || !fillInetSocketAddress(env, clientFd, javaInetSocketAddress, &ss)) {
+ close(clientFd);
+ return NULL;
+ }
+ return (clientFd != -1) ? jniCreateFileDescriptor(env, clientFd) : NULL;
+}
+
static jboolean Posix_access(JNIEnv* env, jobject, jstring javaPath, jint mode) {
ScopedUtfChars path(env, javaPath);
if (path.c_str() == NULL) {
@@ -921,18 +954,7 @@
sockaddr* from = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
socklen_t* fromLength = (javaInetSocketAddress != NULL) ? &sl : 0;
jint recvCount = NET_FAILURE_RETRY("recvfrom", recvfrom(fd, bytes.get() + byteOffset, byteCount, flags, from, fromLength));
- if (recvCount != -1 && javaInetSocketAddress != NULL) {
- // Fill out the passed-in InetSocketAddress with the sender's IP address and port number.
- jint port;
- jobject sender = sockaddrToInetAddress(env, &ss, &port);
- if (sender == NULL) {
- return -1;
- }
- static jfieldID addressFid = env->GetFieldID(JniConstants::inetSocketAddressClass, "addr", "Ljava/net/InetAddress;");
- static jfieldID portFid = env->GetFieldID(JniConstants::inetSocketAddressClass, "port", "I");
- env->SetObjectField(javaInetSocketAddress, addressFid, sender);
- env->SetIntField(javaInetSocketAddress, portFid, port);
- }
+ fillInetSocketAddress(env, recvCount, javaInetSocketAddress, &ss);
return recvCount;
}
@@ -1147,6 +1169,16 @@
return makeStructUtsname(env, buf);
}
+static jint Posix_waitpid(JNIEnv* env, jobject, jint pid, jobject javaStatus, jint options) {
+ int status;
+ int rc = throwIfMinusOne(env, "waitpid", TEMP_FAILURE_RETRY(waitpid(pid, &status, options)));
+ if (rc != -1) {
+ static jfieldID valueFid = env->GetFieldID(JniConstants::mutableIntClass, "value", "I");
+ env->SetIntField(javaStatus, valueFid, status);
+ }
+ return rc;
+}
+
static jint Posix_writeBytes(JNIEnv* env, jobject, jobject javaFd, jbyteArray javaBytes, jint byteOffset, jint byteCount) {
ScopedBytesRO bytes(env, javaBytes);
if (bytes.get() == NULL) {
@@ -1166,6 +1198,7 @@
}
static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Posix, accept, "(Ljava/io/FileDescriptor;Ljava/net/InetSocketAddress;)Ljava/io/FileDescriptor;"),
NATIVE_METHOD(Posix, access, "(Ljava/lang/String;I)Z"),
NATIVE_METHOD(Posix, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
NATIVE_METHOD(Posix, chmod, "(Ljava/lang/String;I)V"),
@@ -1245,6 +1278,7 @@
NATIVE_METHOD(Posix, symlink, "(Ljava/lang/String;Ljava/lang/String;)V"),
NATIVE_METHOD(Posix, sysconf, "(I)J"),
NATIVE_METHOD(Posix, uname, "()Llibcore/io/StructUtsname;"),
+ NATIVE_METHOD(Posix, waitpid, "(ILlibcore/util/MutableInt;I)I"),
NATIVE_METHOD(Posix, writeBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;II)I"),
NATIVE_METHOD(Posix, writev, "(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)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
deleted file mode 100644
index cc2dc49..0000000
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "OSNetworkSystem"
-
-#include "AsynchronousSocketCloseMonitor.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "JniException.h"
-#include "NetFd.h"
-#include "NetworkUtilities.h"
-#include "ScopedLocalRef.h"
-#include "ScopedPrimitiveArray.h"
-#include "jni.h"
-#include "valueOf.h"
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <net/if.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-static void OSNetworkSystem_accept(JNIEnv* env, jobject, jobject serverFileDescriptor,
- jobject newSocket, jobject clientFileDescriptor) {
-
- if (newSocket == NULL) {
- jniThrowNullPointerException(env, NULL);
- return;
- }
-
- NetFd serverFd(env, serverFileDescriptor);
- if (serverFd.isClosed()) {
- return;
- }
-
- sockaddr_storage ss;
- socklen_t addrLen = sizeof(ss);
- sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);
-
- int clientFd;
- {
- int intFd = serverFd.get();
- AsynchronousSocketCloseMonitor monitor(intFd);
- clientFd = NET_FAILURE_RETRY(serverFd, accept(intFd, sa, &addrLen));
- }
- if (env->ExceptionOccurred()) {
- return;
- }
- if (clientFd == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- jniThrowExceptionWithErrno(env, "java/net/SocketTimeoutException", errno);
- } else {
- jniThrowSocketException(env, errno);
- }
- return;
- }
-
- /*
- * For network sockets, put the peer address and port in instance variables.
- * We don't bother to do this for UNIX domain sockets, since most peers are
- * anonymous anyway.
- */
- if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
- jint remotePort;
- jobject remoteAddress = sockaddrToInetAddress(env, &ss, &remotePort);
- if (remoteAddress == NULL) {
- close(clientFd);
- return;
- }
- static jfieldID addressFid = env->GetFieldID(JniConstants::socketImplClass, "address", "Ljava/net/InetAddress;");
- static jfieldID portFid = env->GetFieldID(JniConstants::socketImplClass, "port", "I");
- env->SetObjectField(newSocket, addressFid, remoteAddress);
- env->SetIntField(newSocket, portFid, remotePort);
- }
-
- jniSetFileDescriptorOfFD(env, clientFileDescriptor, clientFd);
-}
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(OSNetworkSystem, accept, "(Ljava/io/FileDescriptor;Ljava/net/SocketImpl;Ljava/io/FileDescriptor;)V"),
-};
-
-int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "org/apache/harmony/luni/platform/OSNetworkSystem", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index c944319..9535ce6 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -18,6 +18,7 @@
java_lang_ProcessManager.cpp \
java_lang_RealToString.cpp \
java_lang_StrictMath.cpp \
+ java_lang_StringToReal.cpp \
java_lang_System.cpp \
java_math_NativeBN.cpp \
java_nio_ByteOrder.cpp \
@@ -43,8 +44,6 @@
libcore_io_OsConstants.cpp \
libcore_io_Posix.cpp \
libcore_net_RawSocket.cpp \
- org_apache_harmony_luni_platform_OSNetworkSystem.cpp \
- org_apache_harmony_luni_util_FloatingPointParser.cpp \
org_apache_harmony_xml_ExpatParser.cpp \
org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp \
readlink.cpp \
diff --git a/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java
index e221675..415ae0a 100644
--- a/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java
@@ -92,6 +92,22 @@
assertEquals(8, fc.write(buffers));
fc.close();
assertEquals(8, tmp.length());
- assertEquals("abcdABCD", new String(IoUtils.readFileAsByteArray(tmp.getPath()), "US-ASCII"));
+ assertEquals("abcdABCD", new String(IoUtils.readFileAsString(tmp.getPath())));
+ }
+
+ public void test_append() throws Exception {
+ File tmp = File.createTempFile("FileChannelTest", "tmp");
+ FileOutputStream fos = new FileOutputStream(tmp, true);
+ FileChannel fc = fos.getChannel();
+
+ fc.write(ByteBuffer.wrap("hello".getBytes("US-ASCII")));
+ fc.position(0);
+ // The RI reports whatever position you set...
+ assertEquals(0, fc.position());
+ // ...but writes to the end of the file.
+ fc.write(ByteBuffer.wrap(" world".getBytes("US-ASCII")));
+ fos.close();
+
+ assertEquals("hello world", new String(IoUtils.readFileAsString(tmp.getPath())));
}
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/OldFileChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/OldFileChannelTest.java
index 9388888..7e2310b 100644
--- a/luni/src/test/java/libcore/java/nio/channels/OldFileChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/OldFileChannelTest.java
@@ -156,11 +156,13 @@
writeOnlyFileChannel.write(writeBuffer);
writeOnlyFileChannel.force(false);
+ fis.close();
readBuffer = new byte[CONTENT_AS_BYTES_LENGTH];
fis = new FileInputStream(fileOfWriteOnlyFileChannel);
fis.read(readBuffer);
assertTrue(Arrays.equals(CONTENT_AS_BYTES, readBuffer));
+ fis.close();
}
diff --git a/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java b/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java
index a5673ff..5981b0b 100644
--- a/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java
+++ b/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java
@@ -27,6 +27,9 @@
import java.lang.reflect.InvocationHandler;
import java.net.CacheRequest;
import java.net.CacheResponse;
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.ResponseCache;
import java.net.SecureCacheResponse;
@@ -63,13 +66,10 @@
import tests.io.MockOs;
public final class HttpResponseCacheTest extends TestCase {
-
- // TODO: test cache + cookies
- // TODO: test cache + user-provided Range header
-
private MockWebServer server = new MockWebServer();
private HttpResponseCache cache;
- final MockOs mockOs = new MockOs();
+ private final MockOs mockOs = new MockOs();
+ private final CookieManager cookieManager = new CookieManager();
@Override protected void setUp() throws Exception {
super.setUp();
@@ -79,6 +79,7 @@
cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE);
ResponseCache.setDefault(cache);
mockOs.install();
+ CookieHandler.setDefault(cookieManager);
}
@Override protected void tearDown() throws Exception {
@@ -86,6 +87,7 @@
server.shutdown();
ResponseCache.setDefault(null);
cache.getCache().delete();
+ CookieHandler.setDefault(null);
super.tearDown();
}
@@ -1499,6 +1501,118 @@
System.out.println("Exercising the cache performs " + (i - 1) + " reads.");
}
+ public void testCachePlusCookies() throws Exception {
+ server.enqueue(new MockResponse()
+ .addHeader("Set-Cookie: a=FIRST; domain=.local;")
+ .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
+ .addHeader("Cache-Control: max-age=0")
+ .setBody("A"));
+ server.enqueue(new MockResponse()
+ .addHeader("Set-Cookie: a=SECOND; domain=.local;")
+ .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
+ server.play();
+
+ URL url = server.getUrl("/");
+ assertEquals("A", readAscii(url.openConnection()));
+ assertCookies(url, "a=FIRST");
+ assertEquals("A", readAscii(url.openConnection()));
+ assertCookies(url, "a=SECOND");
+ }
+
+ public void testGetHeadersReturnsNetworkEndToEndHeaders() throws Exception {
+ server.enqueue(new MockResponse()
+ .addHeader("Allow: GET, HEAD")
+ .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
+ .addHeader("Cache-Control: max-age=0")
+ .setBody("A"));
+ server.enqueue(new MockResponse()
+ .addHeader("Allow: GET, HEAD, PUT")
+ .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
+ server.play();
+
+ URLConnection connection1 = server.getUrl("/").openConnection();
+ assertEquals("A", readAscii(connection1));
+ assertEquals("GET, HEAD", connection1.getHeaderField("Allow"));
+
+ URLConnection connection2 = server.getUrl("/").openConnection();
+ assertEquals("A", readAscii(connection2));
+ assertEquals("GET, HEAD, PUT", connection2.getHeaderField("Allow"));
+ }
+
+ public void testGetHeadersReturnsCachedHopByHopHeaders() throws Exception {
+ server.enqueue(new MockResponse()
+ .addHeader("Transfer-Encoding: identity")
+ .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
+ .addHeader("Cache-Control: max-age=0")
+ .setBody("A"));
+ server.enqueue(new MockResponse()
+ .addHeader("Transfer-Encoding: none")
+ .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
+ server.play();
+
+ URLConnection connection1 = server.getUrl("/").openConnection();
+ assertEquals("A", readAscii(connection1));
+ assertEquals("identity", connection1.getHeaderField("Transfer-Encoding"));
+
+ URLConnection connection2 = server.getUrl("/").openConnection();
+ assertEquals("A", readAscii(connection2));
+ assertEquals("identity", connection2.getHeaderField("Transfer-Encoding"));
+ }
+
+ public void testGetHeadersDeletesCached100LevelWarnings() throws Exception {
+ server.enqueue(new MockResponse()
+ .addHeader("Warning: 199 test danger")
+ .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
+ .addHeader("Cache-Control: max-age=0")
+ .setBody("A"));
+ server.enqueue(new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
+ server.play();
+
+ URLConnection connection1 = server.getUrl("/").openConnection();
+ assertEquals("A", readAscii(connection1));
+ assertEquals("199 test danger", connection1.getHeaderField("Warning"));
+
+ URLConnection connection2 = server.getUrl("/").openConnection();
+ assertEquals("A", readAscii(connection2));
+ assertEquals(null, connection2.getHeaderField("Warning"));
+ }
+
+ public void testGetHeadersRetainsCached200LevelWarnings() throws Exception {
+ server.enqueue(new MockResponse()
+ .addHeader("Warning: 299 test danger")
+ .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
+ .addHeader("Cache-Control: max-age=0")
+ .setBody("A"));
+ server.enqueue(new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
+ server.play();
+
+ URLConnection connection1 = server.getUrl("/").openConnection();
+ assertEquals("A", readAscii(connection1));
+ assertEquals("299 test danger", connection1.getHeaderField("Warning"));
+
+ URLConnection connection2 = server.getUrl("/").openConnection();
+ assertEquals("A", readAscii(connection2));
+ assertEquals("299 test danger", connection2.getHeaderField("Warning"));
+ }
+
+ public void assertCookies(URL url, String... expectedCookies) throws Exception {
+ List<String> actualCookies = new ArrayList<String>();
+ for (HttpCookie cookie : cookieManager.getCookieStore().get(url.toURI())) {
+ actualCookies.add(cookie.toString());
+ }
+ assertEquals(Arrays.asList(expectedCookies), actualCookies);
+ }
+
+ public void testCachePlusRange() throws Exception {
+ assertNotCached(new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_PARTIAL)
+ .addHeader("Date: " + formatDate(0, TimeUnit.HOURS))
+ .addHeader("Content-Range: bytes 100-100/200")
+ .addHeader("Cache-Control: max-age=60"));
+ }
+
/**
* @param delta the offset from the current date to use. Negative
* values yield dates in the past; positive values yield dates in the
diff --git a/luni/src/test/java/libcore/net/http/ParsedHeadersTest.java b/luni/src/test/java/libcore/net/http/ParsedHeadersTest.java
index 0f38a5d..ae684c3 100644
--- a/luni/src/test/java/libcore/net/http/ParsedHeadersTest.java
+++ b/luni/src/test/java/libcore/net/http/ParsedHeadersTest.java
@@ -57,16 +57,15 @@
public void testQuotedFieldName() {
RawHeaders headers = new RawHeaders();
- headers.add("Cache-Control", "private=\"Set-Cookie\"");
+ headers.add("Cache-Control", "private=\"Set-Cookie\", no-store");
ResponseHeaders parsedHeaders = new ResponseHeaders(uri, headers);
- assertEquals("Set-Cookie", parsedHeaders.privateField);
+ assertTrue(parsedHeaders.noStore);
}
public void testUnquotedValue() {
RawHeaders headers = new RawHeaders();
headers.add("Cache-Control", "private=Set-Cookie, no-store");
ResponseHeaders parsedHeaders = new ResponseHeaders(uri, headers);
- assertEquals("Set-Cookie", parsedHeaders.privateField);
assertTrue(parsedHeaders.noStore);
}
@@ -74,7 +73,6 @@
RawHeaders headers = new RawHeaders();
headers.add("Cache-Control", "private=\" a, no-cache, c \", no-store");
ResponseHeaders parsedHeaders = new ResponseHeaders(uri, headers);
- assertEquals(" a, no-cache, c ", parsedHeaders.privateField);
assertTrue(parsedHeaders.noStore);
assertFalse(parsedHeaders.noCache);
}
@@ -83,7 +81,6 @@
RawHeaders headers = new RawHeaders();
headers.add("Cache-Control", "private=\"a, no-cache, c");
ResponseHeaders parsedHeaders = new ResponseHeaders(uri, headers);
- assertEquals("a, no-cache, c", parsedHeaders.privateField);
assertFalse(parsedHeaders.noCache);
}
@@ -92,14 +89,12 @@
headers.add("Cache-Control", "public,");
ResponseHeaders parsedHeaders = new ResponseHeaders(uri, headers);
assertTrue(parsedHeaders.isPublic);
- assertNull(parsedHeaders.privateField);
}
public void testTrailingEquals() {
RawHeaders headers = new RawHeaders();
headers.add("Cache-Control", "private=");
ResponseHeaders parsedHeaders = new ResponseHeaders(uri, headers);
- assertEquals("", parsedHeaders.privateField);
}
public void testSpaceBeforeEquals() {
@@ -145,7 +140,6 @@
headers.add("Cache-Control", "MAX-AGE=60");
headers.add("Cache-Control", "S-MAXAGE=70");
headers.add("Cache-Control", "PUBLIC");
- headers.add("Cache-Control", "PRIVATE=a");
headers.add("Cache-Control", "MUST-REVALIDATE");
ResponseHeaders parsedHeaders = new ResponseHeaders(uri, headers);
assertTrue(parsedHeaders.noCache);
@@ -153,7 +147,6 @@
assertEquals(60, parsedHeaders.maxAgeSeconds);
assertEquals(70, parsedHeaders.sMaxAgeSeconds);
assertTrue(parsedHeaders.isPublic);
- assertEquals("a", parsedHeaders.privateField);
assertTrue(parsedHeaders.mustRevalidate);
}