Merge change I57dd1032
* changes:
Supporting expected results for the jtreg test runner.
diff --git a/logging/src/main/java/java/util/logging/FileHandler.java b/logging/src/main/java/java/util/logging/FileHandler.java
index e1eba9e..dd7790e 100644
--- a/logging/src/main/java/java/util/logging/FileHandler.java
+++ b/logging/src/main/java/java/util/logging/FileHandler.java
@@ -571,7 +571,7 @@
* the log record to publish.
*/
@Override
- public void publish(LogRecord record) {
+ public synchronized void publish(LogRecord record) {
super.publish(record);
flush();
if (limit > 0 && output.getLength() >= limit) {
diff --git a/logging/src/main/java/java/util/logging/LogManager.java b/logging/src/main/java/java/util/logging/LogManager.java
index d7ade24..413efb3 100644
--- a/logging/src/main/java/java/util/logging/LogManager.java
+++ b/logging/src/main/java/java/util/logging/LogManager.java
@@ -401,7 +401,6 @@
* not have the required permissions to perform this action.
*/
public void readConfiguration() throws IOException {
- checkAccess();
// check config class
String configClassName = System
.getProperty("java.util.logging.config.class"); //$NON-NLS-1$
@@ -436,7 +435,7 @@
"logging.properties"), 8192);
}
// END android-added
- readConfigurationImpl(input);
+ readConfiguration(input);
} finally {
if (input != null) {
try {
diff --git a/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java b/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java
index 44389be..3083dc9 100644
--- a/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java
+++ b/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LogManagerTest.java
@@ -837,6 +837,16 @@
assertNull(m.getProperty("java.util.logging.FileHandler.pattern"));
}
+ public void testReadConfiguration() throws SecurityException,
+ IOException {
+
+ MockConfigLogManager lm = new MockConfigLogManager();
+ assertFalse(lm.isCalled);
+
+ lm.readConfiguration();
+ assertTrue(lm.isCalled);
+ }
+
private static void checkProperty(LogManager m) {
// assertEquals(m.getProperty(".level"), "INFO");
assertEquals(m.getProperty("java.util.logging.FileHandler.limit"), "50000");
@@ -1363,6 +1373,15 @@
public static class MockLogManager extends LogManager {
}
+ public static class MockConfigLogManager extends LogManager {
+ public boolean isCalled = false;
+
+ public void readConfiguration(InputStream ins) throws IOException {
+ isCalled = true;
+ super.readConfiguration(ins);
+ }
+ }
+
public static class MockHandler extends Handler {
static int number = 0;
diff --git a/luni/src/main/java/java/io/BufferedReader.java b/luni/src/main/java/java/io/BufferedReader.java
index 77f1975..cfdc4aa 100644
--- a/luni/src/main/java/java/io/BufferedReader.java
+++ b/luni/src/main/java/java/io/BufferedReader.java
@@ -17,6 +17,11 @@
package java.io;
+// BEGIN android-note
+// lots of tidying up of implementation, including renaming fields and changing
+// the implementation of read(char[], int, int)
+// END android-note
+
import org.apache.harmony.luni.util.Msg;
// BEGIN android-added
@@ -44,16 +49,36 @@
private Reader in;
+ /**
+ * The characters that can be read and refilled in bulk. We maintain three
+ * indices into this buffer:<pre>
+ * { X X X X X X X X X X X X - - }
+ * ^ ^ ^
+ * | | |
+ * mark pos end</pre>
+ * Pos points to the next readable character. End is one greater than the
+ * last readable character. When {@code pos == end}, the buffer is empty and
+ * must be {@link #fillBuf() filled} before characters can be read.
+ *
+ * <p>Mark is the value pos will be set to on calls to {@link #reset}. Its
+ * value is in the range {@code [0...pos]}. If the mark is {@code -1}, the
+ * buffer cannot be reset.
+ *
+ * <p>MarkLimit limits the distance between the mark and the pos. When this
+ * limit is exceeded, {@link #reset} is permitted (but not required) to
+ * throw an exception. For shorter distances, {@link #reset} shall not throw
+ * (unless the reader is closed).
+ */
private char[] buf;
- private int marklimit = -1;
-
- private int count;
-
- private int markpos = -1;
-
private int pos;
+ private int end;
+
+ private int mark = -1;
+
+ private int markLimit = -1;
+
/**
* Constructs a new BufferedReader on the Reader {@code in}. The
* buffer gets the default size (8 KB).
@@ -66,7 +91,7 @@
this.in = in;
buf = new char[8192];
- // BEGIN android-added
+ // BEGIN android-only
/*
* For Android, we want to discourage the use of this
* constructor (with its arguably too-large default), so we
@@ -79,7 +104,7 @@
"Default buffer size used in BufferedReader " +
"constructor. It would be " +
"better to be explicit if an 8k-char buffer is required.");
- // END android-added
+ // END android-only
}
/**
@@ -120,36 +145,50 @@
}
}
- private int fillbuf() throws IOException {
- if (markpos == -1 || (pos - markpos >= marklimit)) {
- /* Mark position not set or exceeded readlimit */
+ /**
+ * Populates the buffer with data. It is an error to call this method when
+ * the buffer still contains data; ie. if {@code pos < end}.
+ *
+ * @return the number of bytes read into the buffer, or -1 if the end of the
+ * source stream has been reached.
+ */
+ private int fillBuf() throws IOException {
+ // assert(pos == end);
+
+ if (mark == -1 || (pos - mark >= markLimit)) {
+ /* mark isn't set or has exceeded its limit. use the whole buffer */
int result = in.read(buf, 0, buf.length);
if (result > 0) {
- markpos = -1;
+ mark = -1;
pos = 0;
- count = result == -1 ? 0 : result;
+ end = result;
}
return result;
}
- if (markpos == 0 && marklimit > buf.length) {
- /* Increase buffer size to accommodate the readlimit */
+
+ if (mark == 0 && markLimit > buf.length) {
+ /* the only way to make room when mark=0 is by growing the buffer */
int newLength = buf.length * 2;
- if (newLength > marklimit) {
- newLength = marklimit;
+ if (newLength > markLimit) {
+ newLength = markLimit;
}
char[] newbuf = new char[newLength];
System.arraycopy(buf, 0, newbuf, 0, buf.length);
buf = newbuf;
- } else if (markpos > 0) {
- System.arraycopy(buf, markpos, buf, 0, buf.length - markpos);
+ } else if (mark > 0) {
+ /* make room by shifting the buffered data to left mark positions */
+ System.arraycopy(buf, mark, buf, 0, buf.length - mark);
+ pos -= mark;
+ end -= mark;
+ mark = 0;
}
/* Set the new position and mark position */
- pos -= markpos;
- count = markpos = 0;
- int charsread = in.read(buf, pos, buf.length - pos);
- count = charsread == -1 ? pos : pos + charsread;
- return charsread;
+ int count = in.read(buf, pos, buf.length - pos);
+ if (count != -1) {
+ end += count;
+ }
+ return count;
}
/**
@@ -163,32 +202,32 @@
}
/**
- * Sets a mark position in this reader. The parameter {@code readlimit}
+ * Sets a mark position in this reader. The parameter {@code markLimit}
* indicates how many characters can be read before the mark is invalidated.
* Calling {@code reset()} will reposition the reader back to the marked
- * position if {@code readlimit} has not been surpassed.
+ * position if {@code markLimit} has not been surpassed.
*
- * @param readlimit
+ * @param markLimit
* the number of characters that can be read before the mark is
* invalidated.
* @throws IllegalArgumentException
- * if {@code readlimit < 0}.
+ * if {@code markLimit < 0}.
* @throws IOException
* if an error occurs while setting a mark in this reader.
* @see #markSupported()
* @see #reset()
*/
@Override
- public void mark(int readlimit) throws IOException {
- if (readlimit < 0) {
+ public void mark(int markLimit) throws IOException {
+ if (markLimit < 0) {
throw new IllegalArgumentException();
}
synchronized (lock) {
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
- marklimit = readlimit;
- markpos = pos;
+ this.markLimit = markLimit;
+ mark = pos;
}
}
@@ -224,10 +263,9 @@
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
/* Are there buffered characters available? */
- if (pos < count || fillbuf() != -1) {
+ if (pos < end || fillBuf() != -1) {
return buf[pos++];
}
- markpos = -1;
return -1;
}
}
@@ -276,52 +314,59 @@
throw new IndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$
}
// END android-changed
- if (length == 0) {
- return 0;
- }
- int required;
- if (pos < count) {
- /* There are bytes available in the buffer. */
- int copylength = count - pos >= length ? length : count - pos;
- System.arraycopy(buf, pos, buffer, offset, copylength);
- pos += copylength;
- if (copylength == length || !in.ready()) {
- return copylength;
+
+ int outstanding = length;
+ while (outstanding > 0) {
+
+ /*
+ * If there are bytes in the buffer, grab those first.
+ */
+ int available = end - pos;
+ if (available > 0) {
+ int count = available >= outstanding ? outstanding : available;
+ System.arraycopy(buf, pos, buffer, offset, count);
+ pos += count;
+ offset += count;
+ outstanding -= count;
}
- offset += copylength;
- required = length - copylength;
- } else {
- required = length;
+
+ /*
+ * Before attempting to read from the underlying stream, make
+ * sure we really, really want to. We won't bother if we're
+ * done, or if we've already got some bytes and reading from the
+ * underlying stream would block.
+ */
+ if (outstanding == 0 || (outstanding < length && !in.ready())) {
+ break;
+ }
+
+ // assert(pos == end);
+
+ /*
+ * If we're unmarked and the requested size is greater than our
+ * buffer, read the bytes directly into the caller's buffer. We
+ * don't read into smaller buffers because that could result in
+ * a many reads.
+ */
+ if ((mark == -1 || (pos - mark >= markLimit))
+ && outstanding >= buf.length) {
+ int count = in.read(buffer, offset, outstanding);
+ if (count > 0) {
+ offset += count;
+ outstanding -= count;
+ mark = -1;
+ }
+
+ break; // assume the source stream gave us all that it could
+ }
+
+ if (fillBuf() == -1) {
+ break; // source is exhausted
+ }
}
- while (true) {
- int read;
- /*
- * If we're not marked and the required size is greater than the
- * buffer, simply read the bytes directly bypassing the buffer.
- */
- if (markpos == -1 && required >= buf.length) {
- read = in.read(buffer, offset, required);
- if (read == -1) {
- return required == length ? -1 : length - required;
- }
- } else {
- if (fillbuf() == -1) {
- return required == length ? -1 : length - required;
- }
- read = count - pos >= required ? required : count - pos;
- System.arraycopy(buf, pos, buffer, offset, read);
- pos += read;
- }
- required -= read;
- if (required == 0) {
- return length;
- }
- if (!in.ready()) {
- return length - required;
- }
- offset += read;
- }
+ int count = length - outstanding;
+ return (count > 0 || count == length) ? count : -1;
}
}
@@ -341,11 +386,11 @@
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
- /* Are there buffered characters available? */
- if ((pos >= count) && (fillbuf() == -1)) {
+ /* has the underlying stream been exhausted? */
+ if (pos == end && fillBuf() == -1) {
return null;
}
- for (int charPos = pos; charPos < count; charPos++) {
+ for (int charPos = pos; charPos < end; charPos++) {
char ch = buf[charPos];
// BEGIN android-note
// a switch statement may be more efficient
@@ -360,7 +405,7 @@
} else if (ch == '\r') {
String res = new String(buf, pos, charPos - pos);
pos = charPos + 1;
- if (((pos < count) || (fillbuf() != -1))
+ if (((pos < end) || (fillBuf() != -1))
&& (buf[pos] == '\n')) {
pos++;
}
@@ -372,30 +417,28 @@
StringBuilder result = new StringBuilder(80);
/* Typical Line Length */
- result.append(buf, pos, count - pos);
- pos = count;
+ result.append(buf, pos, end - pos);
while (true) {
+ pos = end;
+
/* Are there buffered characters available? */
- if (pos >= count) {
- if (eol == '\n') {
- return result.toString();
- }
- // attempt to fill buffer
- if (fillbuf() == -1) {
- // characters or null.
- return result.length() > 0 || eol != '\0' ? result
- .toString() : null;
- }
+ if (eol == '\n') {
+ return result.toString();
}
- for (int charPos = pos; charPos < count; charPos++) {
- // BEGIN android-note
- // use a local variable for buf[charPos] and a switch statement
- // END android-note
+ // attempt to fill buffer
+ if (fillBuf() == -1) {
+ // characters or null.
+ return result.length() > 0 || eol != '\0'
+ ? result.toString()
+ : null;
+ }
+ for (int charPos = pos; charPos < end; charPos++) {
+ char c = buf[charPos];
if (eol == '\0') {
- if ((buf[charPos] == '\n' || buf[charPos] == '\r')) {
- eol = buf[charPos];
+ if ((c == '\n' || c == '\r')) {
+ eol = c;
}
- } else if (eol == '\r' && (buf[charPos] == '\n')) {
+ } else if (eol == '\r' && c == '\n') {
if (charPos > pos) {
result.append(buf, pos, charPos - pos - 1);
}
@@ -410,11 +453,10 @@
}
}
if (eol == '\0') {
- result.append(buf, pos, count - pos);
+ result.append(buf, pos, end - pos);
} else {
- result.append(buf, pos, count - pos - 1);
+ result.append(buf, pos, end - pos - 1);
}
- pos = count;
}
}
@@ -437,7 +479,7 @@
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
- return ((count - pos) > 0) || in.ready();
+ return ((end - pos) > 0) || in.ready();
}
}
@@ -457,17 +499,17 @@
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
- if (markpos == -1) {
+ if (mark == -1) {
throw new IOException(Msg.getString("K005c")); //$NON-NLS-1$
}
- pos = markpos;
+ pos = mark;
}
}
/**
* Skips {@code amount} characters in this reader. Subsequent
* {@code read()}s will not return these characters unless {@code reset()}
- * is used. Skipping characters may invalidate a mark if {@code readlimit}
+ * is used. Skipping characters may invalidate a mark if {@code markLimit}
* is surpassed.
*
* @param amount
@@ -493,24 +535,24 @@
if (amount < 1) {
return 0;
}
- if (count - pos >= amount) {
+ if (end - pos >= amount) {
pos += amount;
return amount;
}
- long read = count - pos;
- pos = count;
+ long read = end - pos;
+ pos = end;
while (read < amount) {
- if (fillbuf() == -1) {
+ if (fillBuf() == -1) {
return read;
}
- if (count - pos >= amount - read) {
+ if (end - pos >= amount - read) {
pos += amount - read;
return amount;
}
// Couldn't get all the characters, skip what we read
- read += (count - pos);
- pos = count;
+ read += (end - pos);
+ pos = end;
}
return amount;
}
diff --git a/luni/src/main/java/java/io/PipedInputStream.java b/luni/src/main/java/java/io/PipedInputStream.java
index a6b0336..6d1c007 100644
--- a/luni/src/main/java/java/io/PipedInputStream.java
+++ b/luni/src/main/java/java/io/PipedInputStream.java
@@ -15,6 +15,13 @@
* limitations under the License.
*/
+// BEGIN android-note
+// We've made several changes including:
+// - delayed buffer creation until pipe connection
+// - throw an IOException when a pipe is closed during a write
+// - improved consistency with PipedReader
+// END android-note
+
package java.io;
import org.apache.harmony.luni.util.Msg;
@@ -28,9 +35,11 @@
*/
public class PipedInputStream extends InputStream {
- private Thread lastReader, lastWriter;
+ private Thread lastReader;
- private boolean isClosed = false;
+ private Thread lastWriter;
+
+ private boolean isClosed;
/**
* The circular buffer through which data is passed. Data is read from the
@@ -60,7 +69,7 @@
/**
* The index in {@code buffer} where the next byte will be read.
*/
- protected int out = 0;
+ protected int out;
/**
* The size of the default pipe in bytes.
@@ -70,16 +79,14 @@
/**
* Indicates if this pipe is connected.
*/
- boolean isConnected = false;
+ boolean isConnected;
/**
* Constructs a new unconnected {@code PipedInputStream}. The resulting
* stream must be connected to a {@link PipedOutputStream} before data may
* be read from it.
*/
- public PipedInputStream() {
- /* empty */
- }
+ public PipedInputStream() {}
/**
* Constructs a new {@code PipedInputStream} connected to the
@@ -120,14 +127,9 @@
* if an error occurs while closing this stream.
*/
@Override
- public void close() throws IOException {
- synchronized (this) {
- /* No exception thrown if already closed */
- if (buffer != null) {
- /* Release buffer to indicate closed. */
- buffer = null;
- }
- }
+ public synchronized void close() throws IOException {
+ buffer = null;
+ notifyAll();
}
/**
@@ -145,6 +147,20 @@
}
/**
+ * Establishes the connection to the PipedOutputStream.
+ *
+ * @throws IOException
+ * If this Reader is already connected.
+ */
+ synchronized void establishConnection() throws IOException {
+ if (isConnected) {
+ throw new IOException(Msg.getString("K007a")); //$NON-NLS-1$
+ }
+ buffer = new byte[PipedInputStream.PIPE_SIZE];
+ isConnected = true;
+ }
+
+ /**
* Reads a single byte from this stream and returns it as an integer in the
* range from 0 to 255. Returns -1 if the end of this stream has been
* reached. If there is no data in the pipe, this method blocks until data
@@ -408,20 +424,21 @@
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
- if (buffer != null) {
- if (in == -1) {
- in = 0;
- }
- buffer[in++] = (byte) oneByte;
- if (in == buffer.length) {
- in = 0;
- }
-
- // BEGIN android-added
- // let blocked readers read the newly available data
- notifyAll();
- // END android-added
+ if (buffer == null) {
+ throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
}
+ if (in == -1) {
+ in = 0;
+ }
+ buffer[in++] = (byte) oneByte;
+ if (in == buffer.length) {
+ in = 0;
+ }
+
+ // BEGIN android-added
+ // let blocked readers read the newly available data
+ notifyAll();
+ // END android-added
}
synchronized void done() {
diff --git a/luni/src/main/java/java/io/PipedOutputStream.java b/luni/src/main/java/java/io/PipedOutputStream.java
index 15ee930..4b640d4 100644
--- a/luni/src/main/java/java/io/PipedOutputStream.java
+++ b/luni/src/main/java/java/io/PipedOutputStream.java
@@ -15,6 +15,12 @@
* limitations under the License.
*/
+// BEGIN android-note
+// We've made several changes including:
+// - avoid shallow concurrency problems
+// - improved consistency with PipedWriter
+// END android-note
+
package java.io;
import org.apache.harmony.luni.util.Msg;
@@ -67,8 +73,9 @@
@Override
public void close() throws IOException {
// Is the pipe connected?
- if (dest != null) {
- dest.done();
+ PipedInputStream stream = dest;
+ if (stream != null) {
+ stream.done();
dest = null;
}
}
@@ -83,18 +90,17 @@
* if either stream is already connected.
*/
public void connect(PipedInputStream stream) throws IOException {
- if (null == stream) {
+ if (stream == null) {
throw new NullPointerException();
}
- if (this.dest != null) {
- throw new IOException(Msg.getString("K0079")); //$NON-NLS-1$
- }
synchronized (stream) {
+ if (this.dest != null) {
+ throw new IOException(Msg.getString("K0079")); //$NON-NLS-1$
+ }
if (stream.isConnected) {
throw new IOException(Msg.getString("K007a")); //$NON-NLS-1$
}
- stream.buffer = new byte[PipedInputStream.PIPE_SIZE];
- stream.isConnected = true;
+ stream.establishConnection();
this.dest = stream;
}
}
@@ -108,10 +114,13 @@
*/
@Override
public void flush() throws IOException {
- if (dest != null) {
- synchronized (dest) {
- dest.notifyAll();
- }
+ PipedInputStream stream = dest;
+ if (stream == null) {
+ return;
+ }
+
+ synchronized (stream) {
+ stream.notifyAll();
}
}
@@ -145,13 +154,6 @@
*/
@Override
public void write(byte[] buffer, int offset, int count) throws IOException {
- // BEGIN android-note
- // changed array notation to be consistent with the rest of harmony
- // END android-note
- if (dest == null) {
- // K007b=Pipe Not Connected
- throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
- }
super.write(buffer, offset, count);
}
@@ -177,9 +179,11 @@
*/
@Override
public void write(int oneByte) throws IOException {
- if (dest == null) {
+ PipedInputStream stream = dest;
+ if (stream == null) {
+ // K007b=Pipe Not Connected
throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
}
- dest.receive(oneByte);
+ stream.receive(oneByte);
}
}
diff --git a/luni/src/main/java/java/io/PipedReader.java b/luni/src/main/java/java/io/PipedReader.java
index 251ac90..d137a0d 100644
--- a/luni/src/main/java/java/io/PipedReader.java
+++ b/luni/src/main/java/java/io/PipedReader.java
@@ -17,6 +17,13 @@
package java.io;
+// BEGIN android-note
+// We've made several changes including:
+// - throw an IOException when a pipe is closed during a write
+// - fix shallow concurrency problems, always lock on 'this'
+// - improved consistency with PipedInputStream
+// END android-note
+
import org.apache.harmony.luni.util.Msg;
/**
@@ -35,13 +42,27 @@
private boolean isClosed;
/**
- * The circular buffer through which data is passed.
+ * The circular buffer through which data is passed. Data is read from the
+ * range {@code [out, in)} and written to the range {@code [in, out)}.
+ * Data in the buffer is either sequential: <pre>
+ * { - - - X X X X X X X - - - - - }
+ * ^ ^
+ * | |
+ * out in</pre>
+ * ...or wrapped around the buffer's end: <pre>
+ * { X X X X - - - - - - - - X X X }
+ * ^ ^
+ * | |
+ * in out</pre>
+ * When the buffer is empty, {@code in == -1}. Reading when the buffer is
+ * empty will block until data is available. When the buffer is full,
+ * {@code in == out}. Writing when the buffer is full will block until free
+ * space is available.
*/
- private char data[];
+ private char[] buffer;
/**
- * The index in {@code buffer} where the next character will be
- * written.
+ * The index in {@code buffer} where the next character will be written.
*/
private int in = -1;
@@ -58,18 +79,14 @@
/**
* Indicates if this pipe is connected
*/
- private boolean isConnected;
+ boolean isConnected;
/**
* Constructs a new unconnected {@code PipedReader}. The resulting reader
* must be connected to a {@code PipedWriter} before data may be read from
* it.
- *
- * @see PipedWriter
*/
- public PipedReader() {
- data = new char[PIPE_SIZE];
- }
+ public PipedReader() {}
/**
* Constructs a new {@code PipedReader} connected to the {@link PipedWriter}
@@ -82,7 +99,6 @@
* if {@code out} is already connected.
*/
public PipedReader(PipedWriter out) throws IOException {
- this();
connect(out);
}
@@ -94,14 +110,9 @@
* if an error occurs while closing this reader.
*/
@Override
- public void close() throws IOException {
- synchronized (lock) {
- /* No exception thrown if already closed */
- if (data != null) {
- /* Release buffer to indicate closed. */
- data = null;
- }
- }
+ public synchronized void close() throws IOException {
+ buffer = null;
+ notifyAll();
}
/**
@@ -115,9 +126,7 @@
* src} is already connected.
*/
public void connect(PipedWriter src) throws IOException {
- synchronized (lock) {
- src.connect(this);
- }
+ src.connect(this);
}
/**
@@ -126,16 +135,12 @@
* @throws IOException
* If this Reader is already connected.
*/
- void establishConnection() throws IOException {
- synchronized (lock) {
- if (data == null) {
- throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
- }
- if (isConnected) {
- throw new IOException(Msg.getString("K007a")); //$NON-NLS-1$
- }
- isConnected = true;
+ synchronized void establishConnection() throws IOException {
+ if (isConnected) {
+ throw new IOException(Msg.getString("K007a")); //$NON-NLS-1$
}
+ buffer = new char[PIPE_SIZE];
+ isConnected = true;
}
/**
@@ -192,95 +197,93 @@
* alive.
*/
@Override
- public int read(char[] buffer, int offset, int count) throws IOException {
- synchronized (lock) {
- if (!isConnected) {
- throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
- }
- if (data == null) {
- throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
- }
- // avoid int overflow
- // BEGIN android-changed
- // Exception priorities (in case of multiple errors) differ from
- // RI, but are spec-compliant.
- // made implicit null check explicit,
- // used (offset | count) < 0 instead of (offset < 0) || (count < 0)
- // to safe one operation
- if (buffer == null) {
- throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
- }
- if ((offset | count) < 0 || count > buffer.length - offset) {
- throw new IndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$
- }
- // END android-changed
- if (count == 0) {
- return 0;
- }
- /**
- * Set the last thread to be reading on this PipedReader. If
- * lastReader dies while someone is waiting to write an IOException
- * of "Pipe broken" will be thrown in receive()
- */
- lastReader = Thread.currentThread();
- try {
- boolean first = true;
- while (in == -1) {
- // Are we at end of stream?
- if (isClosed) {
- return -1;
- }
- if (!first && lastWriter != null && !lastWriter.isAlive()) {
- throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
- }
- first = false;
- // Notify callers of receive()
- lock.notifyAll();
- lock.wait(1000);
+ public synchronized int read(char[] buffer, int offset, int count) throws IOException {
+ if (!isConnected) {
+ throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
+ }
+ if (this.buffer == null) {
+ throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
+ }
+ // avoid int overflow
+ // BEGIN android-changed
+ // Exception priorities (in case of multiple errors) differ from
+ // RI, but are spec-compliant.
+ // made implicit null check explicit,
+ // used (offset | count) < 0 instead of (offset < 0) || (count < 0)
+ // to safe one operation
+ if (buffer == null) {
+ throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
+ }
+ if ((offset | count) < 0 || count > buffer.length - offset) {
+ throw new IndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$
+ }
+ // END android-changed
+ if (count == 0) {
+ return 0;
+ }
+ /**
+ * Set the last thread to be reading on this PipedReader. If
+ * lastReader dies while someone is waiting to write an IOException
+ * of "Pipe broken" will be thrown in receive()
+ */
+ lastReader = Thread.currentThread();
+ try {
+ boolean first = true;
+ while (in == -1) {
+ // Are we at end of stream?
+ if (isClosed) {
+ return -1;
}
- } catch (InterruptedException e) {
- throw new InterruptedIOException();
- }
-
- int copyLength = 0;
- /* Copy chars from out to end of buffer first */
- if (out >= in) {
- copyLength = count > data.length - out ? data.length - out
- : count;
- System.arraycopy(data, out, buffer, offset, copyLength);
- out += copyLength;
- if (out == data.length) {
- out = 0;
+ if (!first && lastWriter != null && !lastWriter.isAlive()) {
+ throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
}
- if (out == in) {
- // empty buffer
- in = -1;
- out = 0;
- }
+ first = false;
+ // Notify callers of receive()
+ notifyAll();
+ wait(1000);
}
+ } catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
- /*
- * Did the read fully succeed in the previous copy or is the buffer
- * empty?
- */
- if (copyLength == count || in == -1) {
- return copyLength;
- }
-
- int charsCopied = copyLength;
- /* Copy bytes from 0 to the number of available bytes */
- copyLength = in - out > count - copyLength ? count - copyLength
- : in - out;
- System.arraycopy(data, out, buffer, offset + charsCopied,
- copyLength);
+ int copyLength = 0;
+ /* Copy chars from out to end of buffer first */
+ if (out >= in) {
+ copyLength = count > this.buffer.length - out ? this.buffer.length - out
+ : count;
+ System.arraycopy(this.buffer, out, buffer, offset, copyLength);
out += copyLength;
+ if (out == this.buffer.length) {
+ out = 0;
+ }
if (out == in) {
// empty buffer
in = -1;
out = 0;
}
- return charsCopied + copyLength;
}
+
+ /*
+ * Did the read fully succeed in the previous copy or is the buffer
+ * empty?
+ */
+ if (copyLength == count || in == -1) {
+ return copyLength;
+ }
+
+ int charsCopied = copyLength;
+ /* Copy bytes from 0 to the number of available bytes */
+ copyLength = in - out > count - copyLength ? count - copyLength
+ : in - out;
+ System.arraycopy(this.buffer, out, buffer, offset + charsCopied,
+ copyLength);
+ out += copyLength;
+ if (out == in) {
+ // empty buffer
+ in = -1;
+ out = 0;
+ }
+ return charsCopied + copyLength;
}
/**
@@ -298,16 +301,14 @@
* @see #read(char[], int, int)
*/
@Override
- public boolean ready() throws IOException {
- synchronized (lock) {
- if (!isConnected) {
- throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
- }
- if (data == null) {
- throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
- }
- return in != -1;
+ public synchronized boolean ready() throws IOException {
+ if (!isConnected) {
+ throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
}
+ if (buffer == null) {
+ throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
+ }
+ return in != -1;
}
/**
@@ -324,43 +325,41 @@
* If the stream is already closed or another IOException
* occurs.
*/
- void receive(char oneChar) throws IOException {
- synchronized (lock) {
- if (data == null) {
- throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
- }
- if (lastReader != null && !lastReader.isAlive()) {
- throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
- }
- /*
- * Set the last thread to be writing on this PipedWriter. If
- * lastWriter dies while someone is waiting to read an IOException
- * of "Pipe broken" will be thrown in read()
- */
- lastWriter = Thread.currentThread();
- try {
- while (data != null && out == in) {
- lock.notifyAll();
- // BEGIN android-changed
- lock.wait(1000);
- // END android-changed
- if (lastReader != null && !lastReader.isAlive()) {
- throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
- }
+ synchronized void receive(char oneChar) throws IOException {
+ if (buffer == null) {
+ throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
+ }
+ if (lastReader != null && !lastReader.isAlive()) {
+ throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
+ }
+ /*
+ * Set the last thread to be writing on this PipedWriter. If
+ * lastWriter dies while someone is waiting to read an IOException
+ * of "Pipe broken" will be thrown in read()
+ */
+ lastWriter = Thread.currentThread();
+ try {
+ while (buffer != null && out == in) {
+ notifyAll();
+ // BEGIN android-changed
+ wait(1000);
+ // END android-changed
+ if (lastReader != null && !lastReader.isAlive()) {
+ throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
}
- } catch (InterruptedException e) {
- throw new InterruptedIOException();
}
- if (data != null) {
- if (in == -1) {
- in = 0;
- }
- data[in++] = oneChar;
- if (in == data.length) {
- in = 0;
- }
- return;
- }
+ } catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ if (buffer == null) {
+ throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
+ }
+ if (in == -1) {
+ in = 0;
+ }
+ buffer[in++] = oneChar;
+ if (in == buffer.length) {
+ in = 0;
}
}
@@ -382,80 +381,73 @@
* If the stream is already closed or another IOException
* occurs.
*/
- void receive(char[] chars, int offset, int count) throws IOException {
- synchronized (lock) {
- if (data == null) {
+ synchronized void receive(char[] chars, int offset, int count) throws IOException {
+ if (chars == null) {
+ throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
+ }
+ if ((offset | count) < 0 || count > chars.length - offset) {
+ throw new IndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$
+ }
+ if (buffer == null) {
+ throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
+ }
+ if (lastReader != null && !lastReader.isAlive()) {
+ throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
+ }
+ /**
+ * Set the last thread to be writing on this PipedWriter. If
+ * lastWriter dies while someone is waiting to read an IOException
+ * of "Pipe broken" will be thrown in read()
+ */
+ lastWriter = Thread.currentThread();
+ while (count > 0) {
+ try {
+ while (buffer != null && out == in) {
+ notifyAll();
+ // BEGIN android-changed
+ wait(1000);
+ // END android-changed
+ if (lastReader != null && !lastReader.isAlive()) {
+ throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
+ }
+ }
+ } catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ if (buffer == null) {
throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
}
- if (lastReader != null && !lastReader.isAlive()) {
- throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
+ if (in == -1) {
+ in = 0;
}
- /**
- * Set the last thread to be writing on this PipedWriter. If
- * lastWriter dies while someone is waiting to read an IOException
- * of "Pipe broken" will be thrown in read()
- */
- lastWriter = Thread.currentThread();
- while (count > 0) {
- try {
- while (data != null && out == in) {
- lock.notifyAll();
- // BEGIN android-changed
- lock.wait(1000);
- // END android-changed
- if (lastReader != null && !lastReader.isAlive()) {
- throw new IOException(Msg.getString("K0076")); //$NON-NLS-1$
- }
- }
- } catch (InterruptedException e) {
- throw new InterruptedIOException();
+ if (in >= out) {
+ int length = buffer.length - in;
+ if (count < length) {
+ length = count;
}
- if (data == null) {
- break;
- }
- if (in == -1) {
+ System.arraycopy(chars, offset, buffer, in, length);
+ offset += length;
+ count -= length;
+ in += length;
+ if (in == buffer.length) {
in = 0;
}
- if (in >= out) {
- int length = data.length - in;
- if (count < length) {
- length = count;
- }
- System.arraycopy(chars, offset, data, in, length);
- offset += length;
- count -= length;
- in += length;
- if (in == data.length) {
- in = 0;
- }
- }
- if (count > 0 && in != out) {
- int length = out - in;
- if (count < length) {
- length = count;
- }
- System.arraycopy(chars, offset, data, in, length);
- offset += length;
- count -= length;
- in += length;
- }
}
- if (count == 0) {
- return;
+ if (count > 0 && in != out) {
+ int length = out - in;
+ if (count < length) {
+ length = count;
+ }
+ System.arraycopy(chars, offset, buffer, in, length);
+ offset += length;
+ count -= length;
+ in += length;
}
}
}
- void done() {
- synchronized (lock) {
- isClosed = true;
- lock.notifyAll();
- }
- }
-
- void flush() {
- synchronized (lock) {
- lock.notifyAll();
- }
+ synchronized void done() {
+ isClosed = true;
+ notifyAll();
}
}
diff --git a/luni/src/main/java/java/io/PipedWriter.java b/luni/src/main/java/java/io/PipedWriter.java
index 5fc968d..b0bfa98 100644
--- a/luni/src/main/java/java/io/PipedWriter.java
+++ b/luni/src/main/java/java/io/PipedWriter.java
@@ -15,6 +15,14 @@
* limitations under the License.
*/
+// BEGIN android-note
+// We've made several changes including:
+// - move checks into the synchronized method in PipedReader
+// - reply on PipedReader's isClosed field (rather than having 2 flags)
+// - avoid shallow concurrency problems
+// - improved consistency with PipedOutputStream
+// END android-note
+
package java.io;
import org.apache.harmony.luni.util.Msg;
@@ -32,8 +40,6 @@
*/
private PipedReader dest;
- private boolean closed;
-
/**
* Constructs a new unconnected {@code PipedWriter}. The resulting writer
* must be connected to a {@code PipedReader} before data may be written to
@@ -70,13 +76,10 @@
*/
@Override
public void close() throws IOException {
- synchronized (lock) {
- /* Is the pipe connected? */
- if (dest != null) {
- dest.done();
- dest = null;
- }
- closed = true;
+ PipedReader reader = dest;
+ if (reader != null) {
+ reader.done();
+ dest = null;
}
}
@@ -84,22 +87,26 @@
* Connects this {@code PipedWriter} to a {@link PipedReader}. Any data
* written to this writer becomes readable in the reader.
*
- * @param stream
+ * @param reader
* the reader to connect to.
* @throws IOException
* if this writer is closed or already connected, or if {@code
- * stream} is already connected.
+ * reader} is already connected.
*/
- public void connect(PipedReader stream) throws IOException {
- synchronized (lock) {
+ public void connect(PipedReader reader) throws IOException {
+ if (reader == null) {
+ throw new NullPointerException();
+ }
+ synchronized (reader) {
if (this.dest != null) {
throw new IOException(Msg.getString("K0079")); //$NON-NLS-1$
}
- if (closed) {
+ if (reader.isConnected) {
throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
}
- stream.establishConnection();
- this.dest = stream;
+ reader.establishConnection();
+ this.lock = reader;
+ this.dest = reader;
}
}
@@ -112,8 +119,13 @@
*/
@Override
public void flush() throws IOException {
- if (dest != null) {
- dest.flush();
+ PipedReader reader = dest;
+ if (reader == null) {
+ return;
+ }
+
+ synchronized (reader) {
+ reader.notifyAll();
}
}
@@ -150,32 +162,12 @@
*/
@Override
public void write(char[] buffer, int offset, int count) throws IOException {
- // BEGIN android-note
- // changed array notation to be consistent with the rest of harmony
- // END android-note
- synchronized (lock) {
- if (closed) {
- throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
- }
- if (dest == null) {
- throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
- }
- if (buffer == null) {
- throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
- }
-
- // avoid int overflow
- // BEGIN android-changed
- // Exception priorities (in case of multiple errors) differ from
- // RI, but are spec-compliant.
- // removed redundant check, used (offset | count) < 0
- // instead of (offset < 0) || (count < 0) to safe one operation
- if ((offset | count) < 0 || count > buffer.length - offset) {
- throw new IndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$
- }
- // END android-changed
- dest.receive(buffer, offset, count);
+ PipedReader reader = dest;
+ if (reader == null) {
+ // K007b=Pipe Not Connected
+ throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
}
+ reader.receive(buffer, offset, count);
}
/**
@@ -200,14 +192,11 @@
*/
@Override
public void write(int c) throws IOException {
- synchronized (lock) {
- if (closed) {
- throw new IOException(Msg.getString("K0078")); //$NON-NLS-1$
- }
- if (dest == null) {
- throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
- }
- dest.receive((char) c);
+ PipedReader reader = dest;
+ if (reader == null) {
+ // K007b=Pipe Not Connected
+ throw new IOException(Msg.getString("K007b")); //$NON-NLS-1$
}
+ reader.receive((char) c);
}
}
diff --git a/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java b/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java
index 7ae9de6..cbecab5 100644
--- a/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java
+++ b/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java
@@ -342,7 +342,9 @@
@Override
public void setTimeToLive(int ttl) throws java.io.IOException {
- setOption(IP_MULTICAST_TTL, Byte.valueOf((byte) (ttl & 0xFF)));
+ // BEGIN android-changed: native code wants an int anyway
+ setOption(IP_MULTICAST_TTL, Integer.valueOf(ttl));
+ // END android-changed
if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
this.ttl = ttl;
}
@@ -350,10 +352,9 @@
@Override
public void setTTL(byte ttl) throws java.io.IOException {
- setOption(IP_MULTICAST_TTL, Byte.valueOf(ttl));
- if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
- this.ttl = ttl;
- }
+ // BEGIN android-changed: remove duplication
+ setTimeToLive(ttl);
+ // END android-changed
}
@Override
diff --git a/luni/src/main/native/java_net_NetworkInterface.cpp b/luni/src/main/native/java_net_NetworkInterface.cpp
index abc6e16..52df6e1 100644
--- a/luni/src/main/native/java_net_NetworkInterface.cpp
+++ b/luni/src/main/native/java_net_NetworkInterface.cpp
@@ -20,7 +20,6 @@
#include "jni.h"
#include <errno.h>
-#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
@@ -29,6 +28,8 @@
#include <sys/socket.h>
#include <unistd.h>
+#include <net/if.h> // Note: Can't appear before <sys/socket.h> on OS X.
+
// A smart pointer that closes the given fd on going out of scope.
// TODO: make this generally available.
class scoped_fd {
@@ -74,6 +75,7 @@
jniThrowException(env, "java/lang/OutOfMemoryError", "native heap");
}
+// TODO(enh): move to JNIHelp.h
static void jniThrowSocketException(JNIEnv* env) {
char buf[BUFSIZ];
jniThrowException(env, "java/net/SocketException",
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
index aaa10d3..45319f8 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
@@ -51,9 +51,15 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
-#include <sys/sendfile.h>
#include <sys/uio.h>
+#if HAVE_SYS_SENDFILE_H
+#include <sys/sendfile.h>
+#else
+#include <sys/socket.h>
+#include <sys/types.h>
+#endif
+
static void convertToPlatform(char *path) {
char *pathIndex;
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index 5020ada..33c9119 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -44,7 +44,11 @@
// Temporary hack to build on systems that don't have up-to-date libc headers.
#ifndef IPV6_TCLASS
-#define IPV6_TCLASS 67
+#ifdef __linux__
+#define IPV6_TCLASS 67 // Linux
+#else
+#define IPV6_TCLASS -1 // BSD(-like); TODO: Something better than this!
+#endif
#endif
/**
@@ -112,7 +116,7 @@
#define JAVASOCKOPT_SO_KEEPALIVE 8
#define JAVASOCKOPT_MCAST_TIME_TO_LIVE 10 /* Currently unused */
#define JAVASOCKOPT_SO_BINDADDR 15
-#define JAVASOCKOPT_MCAST_INTERFACE 16
+#define JAVASOCKOPT_IP_MULTICAST_IF 16
#define JAVASOCKOPT_MCAST_TTL 17
#define JAVASOCKOPT_IP_MULTICAST_LOOP 18
#define JAVASOCKOPT_MCAST_ADD_MEMBERSHIP 19
@@ -197,6 +201,9 @@
/**
* Throws an SocketException with the message affiliated with the errorCode.
+ *
+ * @deprecated: 'errorCode' is one of the bogus SOCKERR_ values, *not* errno.
+ * jniThrowSocketException is the better choice.
*/
static void throwSocketException(JNIEnv *env, int errorCode) {
jniThrowException(env, "java/net/SocketException",
@@ -204,26 +211,29 @@
}
// TODO(enh): move to JNIHelp.h
-static void throwNullPointerException(JNIEnv *env) {
- jniThrowException(env, "java/lang/NullPointerException", NULL);
+static void jniThrowSocketException(JNIEnv* env, int error) {
+ char buf[BUFSIZ];
+ jniThrowException(env, "java/net/SocketException",
+ jniStrError(error, buf, sizeof(buf)));
}
// TODO(enh): move to JNIHelp.h
-static void jniThrowAssertionError(JNIEnv* env, const char* message) {
- jniThrowException(env, "java/lang/AssertionError", message);
+static void throwNullPointerException(JNIEnv *env) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
}
// Used by functions that shouldn't throw SocketException. (These functions
// aren't meant to see bad addresses, so seeing one really does imply an
// internal error.)
+// TODO: fix the code (native and Java) so we don't paint ourselves into this corner.
static void jniThrowBadAddressFamily(JNIEnv* env) {
- jniThrowAssertionError(env, "Bad address family");
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Bad address family");
}
static bool jniGetFd(JNIEnv* env, jobject fileDescriptor, int& fd) {
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (fd == -1) {
- throwSocketException(env, SOCKERR_BADDESC);
+ jniThrowSocketException(env, EBADF);
return false;
}
return true;
@@ -293,6 +303,14 @@
addr.s6_addr32[2] == htonl(0xffff));
}
+jobject byteArrayToInetAddress(JNIEnv* env, jbyteArray byteArray) {
+ if (byteArray == NULL) {
+ return NULL;
+ }
+ return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_getbyaddress, byteArray);
+}
+
/**
* Converts a native address structure to an InetAddress object.
* Throws a NullPointerException or an IOException in case of
@@ -304,11 +322,7 @@
*/
jobject socketAddressToInetAddress(JNIEnv* env, sockaddr_storage* sockAddress) {
jbyteArray byteArray = socketAddressToByteArray(env, sockAddress);
- if (byteArray == NULL) {
- return NULL;
- }
- return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
- gCachedFields.iaddr_getbyaddress, byteArray);
+ return byteArrayToInetAddress(env, byteArray);
}
/**
@@ -358,10 +372,10 @@
// Convert the IP address bytes to the proper IP address type.
size_t addressLength = env->GetArrayLength(addressBytes);
+ memset(sockaddress, 0, sizeof(*sockaddress));
if (addressLength == 4) {
// IPv4 address.
sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(sockaddress);
- memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
jbyte* dst = reinterpret_cast<jbyte*>(&sin->sin_addr.s_addr);
@@ -369,7 +383,6 @@
} else if (addressLength == 16) {
// IPv6 address.
sockaddr_in6 *sin6 = reinterpret_cast<sockaddr_in6*>(sockaddress);
- memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
jbyte* dst = reinterpret_cast<jbyte*>(&sin6->sin6_addr.s6_addr);
@@ -399,37 +412,6 @@
}
/**
- * Convert a sockaddr_storage structure to a Java string.
- *
- * @param address pointer to sockaddr_storage structure to convert.
- * @param withPort whether to include the port number in the output as well.
- */
-static bool socketAddressToString(JNIEnv* env,
- sockaddr_storage* address, char* ipString, size_t len) {
- // TODO: getnameinfo seems to want its length parameter to be exactly
- // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
- // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
- // then remove this hack.
- int size;
- if (address->ss_family == AF_INET) {
- size = sizeof(sockaddr_in);
- } else if (address->ss_family == AF_INET6) {
- size = sizeof(sockaddr_in6);
- } else {
- jniThrowBadAddressFamily(env);
- return false;
- }
-
- int rc = getnameinfo((sockaddr*) address, size, ipString, len, NULL,
- 0, NI_NUMERICHOST);
- if (rc != 0) {
- jniThrowException(env, "java/net/UnknownHostException", gai_strerror(rc));
- return false;
- }
- return true;
-}
-
-/**
* Convert a Java byte array representing an IP address to a Java string.
*
* @param addressByteArray the byte array to convert.
@@ -446,8 +428,25 @@
if (!byteArrayToSocketAddress(env, byteArray, 0, &ss)) {
return NULL;
}
+ // TODO: getnameinfo seems to want its length parameter to be exactly
+ // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
+ // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
+ // then remove this hack.
+ int sa_size;
+ if (ss.ss_family == AF_INET) {
+ sa_size = sizeof(sockaddr_in);
+ } else if (ss.ss_family == AF_INET6) {
+ sa_size = sizeof(sockaddr_in6);
+ } else {
+ jniThrowBadAddressFamily(env);
+ return NULL;
+ }
+ // TODO: inet_ntop?
char ipString[INET6_ADDRSTRLEN];
- if (!socketAddressToString(env, &ss, ipString, sizeof(ipString))) {
+ int rc = getnameinfo(reinterpret_cast<sockaddr*>(&ss), sa_size,
+ ipString, sizeof(ipString), NULL, 0, NI_NUMERICHOST);
+ if (rc != 0) {
+ jniThrowException(env, "java/net/UnknownHostException", gai_strerror(rc));
return NULL;
}
return env->NewStringUTF(ipString);
@@ -576,13 +575,8 @@
*
* @return the new Integer
*/
-static jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
- jclass tempClass;
- jmethodID tempMethod;
-
- tempClass = gCachedFields.integer_class;
- tempMethod = gCachedFields.integer_class_init;
- return env->NewObject(tempClass, tempMethod, anInt);
+static jobject newJavaLangInteger(JNIEnv* env, jint anInt) {
+ return env->NewObject(gCachedFields.integer_class, gCachedFields.integer_class_init, anInt);
}
// Converts a number of milliseconds to a timeval.
@@ -869,7 +863,7 @@
*/
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (handle == -1) {
- throwSocketException(env, SOCKERR_INTERRUPTED);
+ jniThrowSocketException(env, EINTR);
return -1;
}
@@ -1149,10 +1143,10 @@
switch(level) {
case SOL_SOCKET:
return "SOL_SOCKET";
- case SOL_IP:
- return "SOL_IP";
- case SOL_IPV6:
- return "SOL_IPV6";
+ case IPPROTO_IP:
+ return "IPPROTO_IP";
+ case IPPROTO_IPV6:
+ return "IPPROTO_IPV6";
default:
return "SOL_???";
}
@@ -1181,11 +1175,11 @@
switch (family) {
case AF_INET:
option = ipv4Option;
- protocol = SOL_IP;
+ protocol = IPPROTO_IP;
break;
case AF_INET6:
option = ipv6Option;
- protocol = SOL_IPV6;
+ protocol = IPPROTO_IPV6;
break;
default:
// TODO(enh): throw Java exceptions from this method instead of just
@@ -1231,20 +1225,19 @@
*/
static int interfaceIndexFromMulticastSocket(int socket) {
int family = getSocketAddressFamily(socket);
- socklen_t requestLength;
int interfaceIndex;
int result;
if (family == AF_INET) {
// IP_MULTICAST_IF returns a pointer to a struct ip_mreqn.
struct ip_mreqn tempRequest;
- requestLength = sizeof(tempRequest);
- result = getsockopt(socket, SOL_IP, IP_MULTICAST_IF, &tempRequest,
+ socklen_t requestLength = sizeof(tempRequest);
+ result = getsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &tempRequest,
&requestLength);
interfaceIndex = tempRequest.imr_ifindex;
} else if (family == AF_INET6) {
// IPV6_MULTICAST_IF returns a pointer to an integer.
- requestLength = sizeof(interfaceIndex);
- result = getsockopt(socket, SOL_IPV6, IPV6_MULTICAST_IF,
+ socklen_t requestLength = sizeof(interfaceIndex);
+ result = getsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
&interfaceIndex, &requestLength);
} else {
errno = EAFNOSUPPORT;
@@ -1305,7 +1298,7 @@
interfaceIndex = interfaceIndexFromMulticastSocket(handle);
multicastRequest.imr_ifindex = interfaceIndex;
if (interfaceIndex == -1) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
}
@@ -1315,16 +1308,16 @@
return;
}
if (sockaddrP.ss_family != AF_INET) {
- throwSocketException(env, SOCKERR_BADAF);
+ jniThrowSocketException(env, EAFNOSUPPORT);
return;
}
struct sockaddr_in *sin = (struct sockaddr_in *) &sockaddrP;
multicastRequest.imr_multiaddr = sin->sin_addr;
- result = setsockopt(handle, SOL_IP, setSockOptVal,
+ result = setsockopt(handle, IPPROTO_IP, setSockOptVal,
&multicastRequest, length);
if (0 != result) {
- throwSocketException (env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
} else {
@@ -1373,7 +1366,7 @@
((struct sockaddr_in *) &sockaddrP)->sin_addr;
ipv4Request.imr_ifindex = interfaceIndex;
multicastRequest = &ipv4Request;
- level = SOL_IP;
+ level = IPPROTO_IP;
break;
case AF_INET6:
// setSockOptVal is passed in by the caller and may be IPv4-only
@@ -1389,18 +1382,18 @@
((struct sockaddr_in6 *) &sockaddrP)->sin6_addr;
ipv6Request.ipv6mr_interface = interfaceIndex;
multicastRequest = &ipv6Request;
- level = SOL_IPV6;
+ level = IPPROTO_IPV6;
break;
default:
- throwSocketException (env, SOCKERR_BADAF);
- return;
+ jniThrowSocketException(env, EAFNOSUPPORT);
+ return;
}
/* join/drop the multicast address */
result = setsockopt(handle, level, setSockOptVal, multicastRequest,
requestLength);
if (0 != result) {
- throwSocketException (env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
}
@@ -1508,8 +1501,7 @@
sock = socket(PF_INET, type, 0);
}
if (sock < 0) {
- int err = convertError(errno);
- throwSocketException(env, err);
+ jniThrowSocketException(env, errno);
return sock;
}
jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
@@ -1555,7 +1547,7 @@
// available, so report "no bytes read".
return 0;
} else {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return 0;
}
}
@@ -1600,7 +1592,7 @@
// it would block, so report "no bytes written".
return 0;
} else {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return 0;
}
}
@@ -1634,7 +1626,7 @@
int block = nonblocking;
int rc = ioctl(handle, FIONBIO, &block);
if (rc == -1) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
}
}
@@ -1720,8 +1712,8 @@
* the descriptor sets that we will use
*/
context =(jbyte *) malloc(sizeof(struct selectFDSet));
- if (NULL == context) {
- throwSocketException(env, SOCKERR_NOBUFFERS);
+ if (context == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "native heap");
return;
}
@@ -1762,7 +1754,7 @@
if (handle == -1) {
sockConnectWithTimeout(handle, address, 0,
SOCKET_STEP_DONE, context);
- throwSocketException(env, SOCKERR_BADDESC);
+ jniThrowSocketException(env, EBADF);
goto bail;
}
@@ -1856,7 +1848,7 @@
int rc = listen(handle, backlog);
if (rc == -1) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
}
@@ -1889,8 +1881,7 @@
result = recv(handle, (jbyte *) message, BUFFERSIZE, MSG_PEEK);
if (0 > result) {
- int err = convertError(errno);
- throwSocketException(env, err);
+ jniThrowSocketException(env, errno);
return 0;
}
return result;
@@ -1921,7 +1912,7 @@
int clientFd = TEMP_FAILURE_RETRY(accept(serverFd,
reinterpret_cast<sockaddr*>(&sa), &addrlen));
if (clientFd == -1) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
@@ -1967,7 +1958,7 @@
int rc = send(handle, &value, 1, MSG_OOB);
if (rc == -1) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
}
}
@@ -1987,7 +1978,7 @@
int ret = doConnect(fd, &sockAddr);
if (ret < 0) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
}
}
@@ -2006,7 +1997,7 @@
int result = doConnect(fd, &sockAddr);
if (result < 0) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
}
}
@@ -2036,7 +2027,7 @@
ssize_t length = TEMP_FAILURE_RETRY(recvfrom(fd, NULL, 0, MSG_PEEK,
reinterpret_cast<sockaddr*>(&sockAddr), &sockAddrLen));
if (length == -1) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return 0;
}
@@ -2074,7 +2065,7 @@
ssize_t actualLength = TEMP_FAILURE_RETRY(recvfrom(fd, buf, length, mode,
reinterpret_cast<sockaddr*>(&sockAddr), &sockAddrLen));
if (actualLength == -1) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return 0;
}
@@ -2199,7 +2190,7 @@
if (errno == ECONNRESET || errno == ECONNREFUSED) {
return 0;
} else {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
}
}
return bytesSent;
@@ -2237,7 +2228,7 @@
if (errno == ECONNRESET || errno == ECONNREFUSED) {
return 0;
} else {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
}
}
return bytesSent;
@@ -2276,7 +2267,7 @@
}
int rc = shutdown(fd, how);
if (rc == -1) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
}
}
@@ -2323,7 +2314,7 @@
SOCKET_NOFLAGS,
reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)));
if (bytesSent == -1) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
free(message);
return 0;
}
@@ -2430,8 +2421,14 @@
sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
memset(&addr, 0, addrLen);
- // Spec says ignore all errors
int rc = getsockname(fd, (sockaddr*) &addr, &addrLen);
+ if (rc == -1) {
+ // TODO: the public API doesn't allow failure, so this whole method
+ // represents a broken design. In practice, though, getsockname can't
+ // fail unless we give it invalid arguments.
+ LOGE("getsockname failed: %s (errno=%i)", strerror(errno), errno);
+ return NULL;
+ }
return socketAddressToInetAddress(env, &addr);
}
@@ -2446,9 +2443,16 @@
sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
- // The java spec does not indicate any exceptions on this call
+ memset(&addr, 0, addrLen);
int rc = getsockname(fd, (sockaddr*) &addr, &addrLen);
- return (rc == -1) ? 0 : getSocketAddressPort(&addr);
+ if (rc == -1) {
+ // TODO: the public API doesn't allow failure, so this whole method
+ // represents a broken design. In practice, though, getsockname can't
+ // fail unless we give it invalid arguments.
+ LOGE("getsockname failed: %s (errno=%i)", strerror(errno), errno);
+ return 0;
+ }
+ return getSocketAddressPort(&addr);
}
static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
@@ -2457,8 +2461,6 @@
int intValue = 0;
socklen_t intSize = sizeof(int);
- unsigned char byteValue = 0;
- socklen_t byteSize = sizeof(unsigned char);
int result;
struct sockaddr_storage sockVal;
socklen_t sockSize = sizeof(sockVal);
@@ -2474,7 +2476,7 @@
socklen_t size = sizeof(struct linger);
result = getsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr, &size);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
if (!lingr.l_onoff) {
@@ -2490,7 +2492,7 @@
}
result = getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intValue, &intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangBoolean(env, intValue);
@@ -2504,22 +2506,26 @@
IPV6_MULTICAST_HOPS, &intValue,
&intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangByte(env, (jbyte)(intValue & 0xFF));
}
- case JAVASOCKOPT_MCAST_INTERFACE: {
+ case JAVASOCKOPT_IP_MULTICAST_IF: {
if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
return NULL;
}
- result = getsockopt(handle, SOL_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
- if (0 != result) {
- throwSocketException(env, convertError(errno));
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
+ &sockVal, &sockSize);
+ if (result == -1) {
+ jniThrowSocketException(env, errno);
return NULL;
}
- // This option is IPv4-only.
- sockVal.ss_family = AF_INET;
+ if (sockVal.ss_family != AF_INET) {
+ // Java expects an AF_INET INADDR_ANY, but Linux just returns AF_UNSPEC.
+ jbyteArray inAddrAny = env->NewByteArray(4); // { 0, 0, 0, 0 }
+ return byteArrayToInetAddress(env, inAddrAny);
+ }
return socketAddressToInetAddress(env, &sockVal);
}
case JAVASOCKOPT_IP_MULTICAST_IF2: {
@@ -2527,38 +2533,37 @@
return NULL;
}
struct ip_mreqn multicastRequest;
- int interfaceIndex;
+ int interfaceIndex = 0;
socklen_t optionLength;
int addressFamily = getSocketAddressFamily(handle);
switch (addressFamily) {
case AF_INET:
optionLength = sizeof(multicastRequest);
- result = getsockopt(handle, SOL_IP, IP_MULTICAST_IF,
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
&multicastRequest, &optionLength);
if (result == 0)
interfaceIndex = multicastRequest.imr_ifindex;
break;
case AF_INET6:
optionLength = sizeof(interfaceIndex);
- result = getsockopt(handle, SOL_IPV6, IPV6_MULTICAST_IF,
+ result = getsockopt(handle, IPPROTO_IPV6, IPV6_MULTICAST_IF,
&interfaceIndex, &optionLength);
break;
default:
- throwSocketException(env, SOCKERR_BADAF);
+ jniThrowSocketException(env, EAFNOSUPPORT);
return NULL;
}
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
-
return newJavaLangInteger(env, interfaceIndex);
}
case JAVASOCKOPT_SO_SNDBUF: {
result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangInteger(env, intValue);
@@ -2566,7 +2571,7 @@
case JAVASOCKOPT_SO_RCVBUF: {
result = getsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intValue, &intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangInteger(env, intValue);
@@ -2574,7 +2579,7 @@
case JAVASOCKOPT_SO_BROADCAST: {
result = getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intValue, &intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangBoolean(env, intValue);
@@ -2582,7 +2587,7 @@
case JAVASOCKOPT_SO_REUSEADDR: {
result = getsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intValue, &intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangBoolean(env, intValue);
@@ -2590,7 +2595,7 @@
case JAVASOCKOPT_SO_KEEPALIVE: {
result = getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intValue, &intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangBoolean(env, intValue);
@@ -2598,7 +2603,7 @@
case JAVASOCKOPT_SO_OOBINLINE: {
result = getsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intValue, &intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangBoolean(env, intValue);
@@ -2609,7 +2614,7 @@
IPV6_MULTICAST_LOOP, &intValue,
&intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangBoolean(env, intValue);
@@ -2618,7 +2623,7 @@
result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_TOS,
IPV6_TCLASS, &intValue, &intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangInteger(env, intValue);
@@ -2628,13 +2633,13 @@
socklen_t size = sizeof(timeout);
result = getsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout, &size);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return NULL;
}
return newJavaLangInteger(env, toMs(timeout));
}
default: {
- throwSocketException(env, SOCKERR_OPTUNSUPP);
+ jniThrowSocketException(env, ENOPROTOOPT);
return NULL;
}
}
@@ -2648,8 +2653,6 @@
int result;
int intVal;
socklen_t intSize = sizeof(int);
- unsigned char byteVal;
- socklen_t byteSize = sizeof(unsigned char);
struct sockaddr_storage sockVal;
int sockSize = sizeof(sockVal);
@@ -2658,7 +2661,8 @@
} else if (env->IsInstanceOf(optVal, gCachedFields.boolean_class)) {
intVal = (int) env->GetBooleanField(optVal, gCachedFields.boolean_class_value);
} else if (env->IsInstanceOf(optVal, gCachedFields.byte_class)) {
- byteVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
+ // TTL uses a byte in Java, but the kernel still wants an int.
+ intVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
} else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
if (!inetAddressToSocketAddress(env, optVal, 0, &sockVal)) {
return;
@@ -2666,7 +2670,7 @@
} else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
// we'll use optVal directly
} else {
- throwSocketException(env, SOCKERR_OPTUNSUPP);
+ jniThrowSocketException(env, ENOPROTOOPT);
return;
}
@@ -2683,7 +2687,7 @@
result = setsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr,
sizeof(struct linger));
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2695,7 +2699,7 @@
}
result = setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intVal, intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2705,13 +2709,11 @@
if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
return;
}
- // Java uses a byte to store the TTL, but the kernel uses an int.
- intVal = byteVal;
result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_MULTICAST_TTL,
IPV6_MULTICAST_HOPS, &intVal,
&intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2729,24 +2731,24 @@
break;
}
- case JAVASOCKOPT_MCAST_INTERFACE: {
+ case JAVASOCKOPT_IP_MULTICAST_IF: {
if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
return;
}
// This call is IPv4 only. The socket may be IPv6, but the address
// that identifies the interface to join must be an IPv4 address.
if (sockVal.ss_family != AF_INET) {
- throwSocketException(env, SOCKERR_BADAF);
+ jniThrowSocketException(env, EAFNOSUPPORT);
return;
}
struct ip_mreqn mcast_req;
memset(&mcast_req, 0, sizeof(mcast_req));
struct sockaddr_in *sin = (struct sockaddr_in *) &sockVal;
mcast_req.imr_address = sin->sin_addr;
- result = setsockopt(handle, SOL_IP, IP_MULTICAST_IF,
+ result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
&mcast_req, sizeof(mcast_req));
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2775,14 +2777,14 @@
optionLength = sizeof(interfaceIndex);
break;
default:
- throwSocketException(env, SOCKERR_BADAF);
+ jniThrowSocketException(env, EAFNOSUPPORT);
return;
}
result = getOrSetSocketOption(SOCKOPT_SET, handle,
IP_MULTICAST_IF, IPV6_MULTICAST_IF, optionValue,
&optionLength);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2791,7 +2793,7 @@
case JAVASOCKOPT_SO_SNDBUF: {
result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2800,7 +2802,7 @@
case JAVASOCKOPT_SO_RCVBUF: {
result = setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intVal, intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2809,7 +2811,7 @@
case JAVASOCKOPT_SO_BROADCAST: {
result = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intVal, intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2818,7 +2820,7 @@
case JAVASOCKOPT_SO_REUSEADDR: {
result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2826,7 +2828,7 @@
case JAVASOCKOPT_SO_KEEPALIVE: {
result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intVal, intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2835,7 +2837,7 @@
case JAVASOCKOPT_SO_OOBINLINE: {
result = setsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intVal, intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2847,7 +2849,7 @@
IPV6_MULTICAST_LOOP, &intVal,
&intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2857,7 +2859,7 @@
result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_TOS,
IPV6_TCLASS, &intVal, &intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2867,7 +2869,7 @@
// SO_REUSEPORT doesn't need to get set on this System
result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
@@ -2878,14 +2880,14 @@
result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(struct timeval));
if (0 != result) {
- throwSocketException(env, convertError(errno));
+ jniThrowSocketException(env, errno);
return;
}
break;
}
default: {
- throwSocketException(env, SOCKERR_OPTUNSUPP);
+ jniThrowSocketException(env, ENOPROTOOPT);
}
}
}
diff --git a/luni/src/test/java/java/net/AllTests.java b/luni/src/test/java/java/net/AllTests.java
new file mode 100644
index 0000000..6d26f0d
--- /dev/null
+++ b/luni/src/test/java/java/net/AllTests.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2009 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 java.net;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+ public static final Test suite() {
+ TestSuite suite = tests.TestSuiteFactory.createTestSuite();
+ suite.addTestSuite(java.net.SocketTest.class);
+ return suite;
+ }
+}
diff --git a/luni/src/test/java/java/net/SocketTest.java b/luni/src/test/java/java/net/SocketTest.java
new file mode 100644
index 0000000..b0e278f
--- /dev/null
+++ b/luni/src/test/java/java/net/SocketTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 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 java.net;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class SocketTest extends junit.framework.TestCase {
+ /**
+ * Our getLocalAddress and getLocalPort currently use getsockname(3).
+ * This means they give incorrect results on closed sockets (as well
+ * as requiring an unnecessary call into native code).
+ */
+ public void test_getLocalAddress_after_close() throws Exception {
+ Socket s = new Socket();
+ try {
+ // Bind to an ephemeral local port.
+ s.bind(new InetSocketAddress("localhost", 0));
+ assertTrue(s.getLocalAddress().isLoopbackAddress());
+ // What local port did we get?
+ int localPort = s.getLocalPort();
+ assertTrue(localPort > 0);
+ // Now close the socket...
+ s.close();
+ // The RI returns the ANY address but the original local port after close.
+ assertTrue(s.getLocalAddress().isAnyLocalAddress());
+ assertEquals(localPort, s.getLocalPort());
+ } finally {
+ s.close();
+ }
+ }
+}
diff --git a/luni/src/test/java/tests/AllTests.java b/luni/src/test/java/tests/AllTests.java
index 7d12bcc..d2799ec 100644
--- a/luni/src/test/java/tests/AllTests.java
+++ b/luni/src/test/java/tests/AllTests.java
@@ -59,6 +59,7 @@
suite.addTest(com.ibm.icu4jni.util.AllTests.suite());
suite.addTest(java.lang.AllTests.suite());
suite.addTest(java.lang.reflect.AllTests.suite());
+ suite.addTest(java.net.AllTests.suite());
suite.addTest(org.apache.harmony.luni.platform.AllTests.suite());
suite.addTest(tests.api.org.apache.harmony.kernel.dalvik.AllTests.suite());
diff --git a/luni/src/test/java/tests/api/java/io/BufferedReaderTest.java b/luni/src/test/java/tests/api/java/io/BufferedReaderTest.java
index b1a5755..f88b3f5 100644
--- a/luni/src/test/java/tests/api/java/io/BufferedReaderTest.java
+++ b/luni/src/test/java/tests/api/java/io/BufferedReaderTest.java
@@ -24,12 +24,14 @@
import java.io.InputStreamReader;
import java.io.PipedReader;
import java.io.Reader;
+import java.io.StringReader;
import tests.support.Support_ASimpleReader;
import tests.support.Support_StringReader;
import dalvik.annotation.TestLevel;
import dalvik.annotation.TestTargetClass;
import dalvik.annotation.TestTargetNew;
+import tests.support.ThrowingReader;
@TestTargetClass(BufferedReader.class)
public class BufferedReaderTest extends junit.framework.TestCase {
@@ -502,6 +504,33 @@
ssr.throwExceptionOnNextUse = false;
}
+ public void testReadZeroLengthArray() throws IOException {
+ br = new BufferedReader(new Support_StringReader("ABCDEF"));
+ br.read();
+ br.read();
+ assertEquals(0, br.read(new char[6], 3, 0));
+ }
+
+ public void testSourceThrowsWithMark() throws IOException {
+ br = new BufferedReader(new ThrowingReader(
+ new StringReader("ABCDEFGHI"), 4));
+
+ br.read();
+ br.read();
+ br.mark(10);
+ br.read();
+ br.read();
+
+ try {
+ br.read();
+ fail();
+ } catch (IOException fromThrowingReader) {
+ }
+
+ assertEquals('E', br.read());
+ assertEquals('F', br.read());
+ }
+
/**
* Tears down the fixture, for example, close a network connection. This
* method is called after a test is executed.
diff --git a/math/src/main/java/java/math/BigInt.java b/math/src/main/java/java/math/BigInt.java
index 581c22f..3ba1da2 100644
--- a/math/src/main/java/java/math/BigInt.java
+++ b/math/src/main/java/java/math/BigInt.java
@@ -234,9 +234,9 @@
else if (val < 0) NativeBN.BN_set_negative(this.bignum, 1);
}
-
- public boolean twosCompFitsIntoBytes(int byteCnt) {
- return NativeBN.twosCompFitsIntoBytes(this.bignum, byteCnt);
+ public boolean twosCompFitsIntoBytes(int desiredByteCount) {
+ int actualByteCount = (NativeBN.bitLength(this.bignum) + 7) / 8;
+ return actualByteCount <= desiredByteCount;
}
public int bitLength() {
diff --git a/openssl/src/main/java/org/openssl/NativeBN.java b/openssl/src/main/java/org/openssl/NativeBN.java
index 3597e3c..fd796f8 100644
--- a/openssl/src/main/java/org/openssl/NativeBN.java
+++ b/openssl/src/main/java/org/openssl/NativeBN.java
@@ -86,9 +86,6 @@
public static native void BN_set_negative(int b, int n);
// void BN_set_negative(BIGNUM *b, int n);
-
- public static native boolean twosCompFitsIntoBytes(int a, int byteCnt);
-
public static native int bitLength(int a);
public static native boolean BN_is_bit_set(int a, int n);
diff --git a/openssl/src/main/native/BNInterface.c b/openssl/src/main/native/BNInterface.c
index 1a3eb16..79f0680 100644
--- a/openssl/src/main/native/BNInterface.c
+++ b/openssl/src/main/native/BNInterface.c
@@ -469,60 +469,6 @@
BN_set_negative(b, n);
}
-
-/**
- * public static native int twosCompFitsIntoBytes(int, int)
- */
-static jboolean NativeBN_twosCompFitsIntoBytes(JNIEnv* env, jclass cls, BIGNUM* a, int byteCnt) {
-// byteCnt IN {1, 2, 4, 8, 12, 16, ... (k * 4)}
-// We rely on: (BN_BITS2 == 32), i.e. BN_ULONG is unsigned int and has 4 bytes:
-//
-// LOGD("NativeBN_twosCompFitsIntoBytes");
- if (!oneValidHandle(env, a)) return FALSE;
- bn_check_top(a);
- int intLen = a->top;
- BN_ULONG* d = a->d;
- BN_ULONG msd; // most significant digit
- switch (byteCnt) {
- case 1:
- if (intLen > 1) return FALSE;
- else if (intLen == 0) return TRUE;
- msd = d[0];
- if (a->neg) msd--;
- return ((msd & 0XFFFFFF80) == 0);
- case 2:
- if (intLen > 1) return FALSE;
- else if (intLen == 0) return TRUE;
- msd = d[0];
- if (a->neg) msd--;
- return ((msd & 0XFFFF8000) == 0);
- case 4:
- if (intLen > 1) return FALSE;
- else if (intLen == 0) return TRUE;
- msd = d[0];
- if (a->neg) msd--;
- return ((msd & 0X80000000) == 0);
- case 8:
- if (intLen > 2) return FALSE;
- else if (intLen == 0) return TRUE;
- msd = d[1];
- if ((a->neg) && (d[0]) == 0) msd--;
- return ((msd & 0X80000000) == 0);
- default:
- if (intLen > byteCnt / 4) return FALSE;
- else if (intLen == 0) return TRUE;
- int i = intLen - 1;
- msd = d[i];
- if (a->neg) {
- // Handle negative values correctly:
- // i.e. decrement the msd if all other digits are 0:
- do { i--; } while (!((i < 0) || (d[i] != 0)));
- if (i < 0) msd--; // Only if all lower significant digits are 0 we decrement the most significant one.
- }
- return ((msd & 0X80000000) == 0);
- }
-}
-
/**
* public static native int bitLength(int)
*/
@@ -547,15 +493,6 @@
}
/**
- * public static native int BN_num_bits(int)
- */
-// static int NativeBN_BN_num_bits(JNIEnv* env, jclass cls, BIGNUM* a) {
-// LOGD("NativeBN_BN_num_bits");
-// if (!oneValidHandle(env, a)) return FALSE;
-// return BN_num_bits(a);
-// }
-
-/**
* public static native boolean BN_is_bit_set(int, int)
*/
static jboolean NativeBN_BN_is_bit_set(JNIEnv* env, jclass cls, BIGNUM* a, int n) {
@@ -808,9 +745,7 @@
{ "bn2litEndInts", "(I[I)[I", (void*)NativeBN_bn2litEndInts },
{ "sign", "(I)I", (void*)NativeBN_sign },
{ "BN_set_negative", "(II)V", (void*)NativeBN_BN_set_negative },
- { "twosCompFitsIntoBytes", "(II)Z", (void*)NativeBN_twosCompFitsIntoBytes },
{ "bitLength", "(I)I", (void*)NativeBN_bitLength },
-// { "BN_num_bits", "(I)I", (void*)NativeBN_BN_num_bits },
{ "BN_is_bit_set", "(II)Z", (void*)NativeBN_BN_is_bit_set },
{ "modifyBit", "(III)Z", (void*)NativeBN_modifyBit },
{ "BN_lshift", "(III)Z", (void*)NativeBN_BN_lshift },
@@ -832,19 +767,6 @@
{ "BN_is_prime_ex", "(IIII)Z", (void*)NativeBN_BN_is_prime_ex }
};
-/*
- * Peforms the actual registration of the native methods.
- * Also looks up the fields that belong to the class (if
- * any) and stores the field IDs.
- */
int register_org_openssl_NativeBN(JNIEnv* env) {
-/*
- jclass clazz;
-
- clazz = (*env)->FindClass(env, "org/openssl/NativeBN");
- if (clazz == NULL) {
- return -1;
- }
-*/
return jniRegisterNativeMethods(env, "org/openssl/NativeBN", METHODS, NELEM(METHODS));
}
diff --git a/support/src/test/java/tests/support/ThrowingReader.java b/support/src/test/java/tests/support/ThrowingReader.java
new file mode 100644
index 0000000..fbefeb1
--- /dev/null
+++ b/support/src/test/java/tests/support/ThrowingReader.java
@@ -0,0 +1,64 @@
+/*
+ * 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 tests.support;
+
+import java.io.FilterReader;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A reader that always throws after a predetermined number of bytes have been
+ * read.
+ */
+public class ThrowingReader extends FilterReader {
+
+ private int total = 0;
+ private int throwAt;
+
+ public ThrowingReader(Reader in, int throwAt) {
+ super(in);
+ this.throwAt = throwAt;
+ }
+
+ @Override public int read() throws IOException {
+ explodeIfNecessary();
+ int result = super.read();
+ total++;
+ return result;
+ }
+
+ @Override public int read(char[] buf, int offset, int count)
+ throws IOException {
+ explodeIfNecessary();
+
+ if (total < throwAt) {
+ count = Math.min(count, (throwAt - total));
+ }
+
+ int returned = super.read(buf, offset, count);
+ total += returned;
+ return returned;
+ }
+
+ private void explodeIfNecessary() throws IOException {
+ if (total == throwAt) {
+ throwAt = Integer.MAX_VALUE;
+ throw new IOException();
+ }
+ }
+}
diff --git a/tools/integrate/Module.java b/tools/integrate/Module.java
index 63d35a2..02cdb6a 100644
--- a/tools/integrate/Module.java
+++ b/tools/integrate/Module.java
@@ -48,6 +48,8 @@
"crypto/src/test/java")
.build());
+ valuesMutable.put("logging", new Module.Builder(svnRoot, "logging").build());
+
valuesMutable.put("regex", new Module.Builder(svnRoot, "regex").build());
valuesMutable.put("security", new Module.Builder(svnRoot, "security")