diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index e0f4009c7a..d75727922e 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -149,46 +149,12 @@ throwSocketException(JNIEnv* e) throwSocketException(e, errorString(e)); } -void -init(JNIEnv* e, sockaddr_in* address, jstring hostString, jint port) +void init(sockaddr_in* address, jint host, jint port) { - const char* chars = e->GetStringUTFChars(hostString, 0); - if (chars) { -#ifdef PLATFORM_WINDOWS - hostent* host = gethostbyname(chars); - e->ReleaseStringUTFChars(hostString, chars); - if (host == 0) { - throwIOException(e); - return; - } - - memset(address, 0, sizeof(sockaddr_in)); - address->sin_family = AF_INET; - address->sin_port = htons(port); - address->sin_addr = *reinterpret_cast(host->h_addr_list[0]); -#else - addrinfo hints; - memset(&hints, 0, sizeof(addrinfo)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - addrinfo* result; - int r = getaddrinfo(chars, 0, &hints, &result); - e->ReleaseStringUTFChars(hostString, chars); - if (r != 0) { - throwIOException(e, gai_strerror(r)); - return; - } - - memset(address, 0, sizeof(sockaddr_in)); - address->sin_family = AF_INET; - address->sin_port = htons(port); - address->sin_addr = reinterpret_cast - (result->ai_addr)->sin_addr; - - freeaddrinfo(result); -#endif - } + memset(address, 0, sizeof(sockaddr_in)); + address->sin_family = AF_INET; + address->sin_port = htons(port); + address->sin_addr.s_addr = htonl(host); } inline bool @@ -384,8 +350,17 @@ doWrite(int fd, const void* buffer, size_t count) #endif } -int -makeSocket(JNIEnv* e, int type = SOCK_STREAM, int protocol = IPPROTO_TCP) +int doSend(int fd, sockaddr_in* address, const void* buffer, size_t count) +{ + return sendto(fd, + static_cast(buffer), + count, + 0, + reinterpret_cast(address), + sizeof(sockaddr_in)); +} + +int makeSocket(JNIEnv* e, int type = SOCK_STREAM, int protocol = IPPROTO_TCP) { int s = ::socket(AF_INET, type, protocol); if (s < 0) { @@ -405,43 +380,44 @@ Java_java_nio_channels_ServerSocketChannel_natDoAccept(JNIEnv *e, jclass, jint s return ::doAccept(e, socket); } -extern "C" JNIEXPORT jint JNICALL -Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv *e, - jclass, - jstring host, - jint port) +extern "C" JNIEXPORT void JNICALL + Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv* e, + jclass, + jint socket, + jint host, + jint port) { - int s = makeSocket(e); - if (s < 0) return s; - if (e->ExceptionCheck()) return 0; - sockaddr_in address; - init(e, &address, host, port); - if (e->ExceptionCheck()) return 0; + init(&address, host, port); - ::doBind(e, s, &address); - if (e->ExceptionCheck()) return 0; + ::doBind(e, socket, &address); + if (e->ExceptionCheck()) + return; - ::doListen(e, s); - return s; + ::doListen(e, socket); } -extern "C" JNIEXPORT jint JNICALL -Java_java_nio_channels_DatagramChannel_bind(JNIEnv *e, - jclass, - jstring host, - jint port) +extern "C" JNIEXPORT void JNICALL + Java_java_nio_channels_SocketChannel_bind(JNIEnv* e, + jclass, + jint socket, + jint host, + jint port) { - int s = makeSocket(e, SOCK_DGRAM, IPPROTO_UDP); - if (s < 0) return s; - if (e->ExceptionCheck()) return 0; - sockaddr_in address; - init(e, &address, host, port); - if (e->ExceptionCheck()) return 0; + init(&address, host, port); - ::doBind(e, s, &address); - return s; + ::doBind(e, socket, &address); +} + +extern "C" JNIEXPORT void JNICALL + Java_java_nio_channels_DatagramChannel_bind(JNIEnv* e, + jclass c, + jint socket, + jint host, + jint port) +{ + Java_java_nio_channels_SocketChannel_bind(e, c, socket, host, port); } extern "C" JNIEXPORT void JNICALL @@ -472,45 +448,42 @@ Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e, setTcpNoDelay(e, socket, on); } -extern "C" JNIEXPORT jint JNICALL -Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e, - jclass, - jstring host, - jint port, - jboolean blocking, - jbooleanArray retVal) +extern "C" JNIEXPORT jboolean JNICALL + Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv* e, + jclass, + jint socket, + jint host, + jint port) { - int s = makeSocket(e); - if (e->ExceptionCheck()) return 0; - - setBlocking(e, s, blocking); - sockaddr_in address; - init(e, &address, host, port); - if (e->ExceptionCheck()) return 0; - - jboolean connected = ::doConnect(e, s, &address); - e->SetBooleanArrayRegion(retVal, 0, 1, &connected); - - return s; + init(&address, host, port); + + return ::doConnect(e, socket, &address); } extern "C" JNIEXPORT jint JNICALL -Java_java_nio_channels_DatagramChannel_connect(JNIEnv *e, - jclass, - jstring host, - jint port) + Java_java_nio_channels_SocketChannel_makeSocket(JNIEnv* e, jclass) { - int s = makeSocket(e, SOCK_DGRAM, IPPROTO_UDP); - if (e->ExceptionCheck()) return 0; + return makeSocket(e); +} +extern "C" JNIEXPORT jint JNICALL + Java_java_nio_channels_DatagramChannel_makeSocket(JNIEnv* e, jclass) +{ + return makeSocket(e, SOCK_DGRAM, IPPROTO_UDP); +} + +extern "C" JNIEXPORT jboolean JNICALL + Java_java_nio_channels_DatagramChannel_connect(JNIEnv* e, + jclass, + jint socket, + jint host, + jint port) +{ sockaddr_in address; - init(e, &address, host, port); - if (e->ExceptionCheck()) return 0; - - ::doConnect(e, s, &address); - - return s; + init(&address, host, port); + + return ::doConnect(e, socket, &address); } extern "C" JNIEXPORT void JNICALL @@ -669,6 +642,51 @@ Java_java_nio_channels_DatagramChannel_write(JNIEnv* e, (e, c, socket, buffer, offset, length, blocking); } +extern "C" JNIEXPORT jint JNICALL + Java_java_nio_channels_DatagramChannel_send(JNIEnv* e, + jclass, + jint socket, + jint host, + jint port, + jbyteArray buffer, + jint offset, + jint length, + jboolean blocking) +{ + sockaddr_in address; + init(&address, host, port); + + int r; + if (blocking) { + uint8_t* buf = static_cast(allocate(e, length)); + if (buf) { + e->GetByteArrayRegion( + buffer, offset, length, reinterpret_cast(buf)); + r = ::doSend(socket, &address, buf, length); + free(buf); + } else { + return 0; + } + } else { + jboolean isCopy; + uint8_t* buf + = static_cast(e->GetPrimitiveArrayCritical(buffer, &isCopy)); + + r = ::doSend(socket, &address, buf + offset, length); + + e->ReleasePrimitiveArrayCritical(buffer, buf, 0); + } + + if (r < 0) { + if (eagain()) { + return 0; + } else { + throwIOException(e); + } + } + return r; +} + extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e, jclass, @@ -693,6 +711,14 @@ Java_java_nio_channels_SocketChannel_natCloseSocket(JNIEnv *, doClose(socket); } +extern "C" JNIEXPORT void JNICALL +Java_java_nio_channels_DatagramChannel_close(JNIEnv *, + jclass, + jint socket) +{ + doClose(socket); +} + namespace { class Pipe { diff --git a/classpath/java/io/Reader.java b/classpath/java/io/Reader.java index da95526caa..5a655bcdd1 100644 --- a/classpath/java/io/Reader.java +++ b/classpath/java/io/Reader.java @@ -10,7 +10,21 @@ package java.io; -public abstract class Reader implements Closeable { +import java.nio.CharBuffer; + +public abstract class Reader implements Closeable, Readable { + public int read(CharBuffer buffer) throws IOException { + int c = read(buffer.array(), + buffer.arrayOffset() + buffer.position(), + buffer.remaining()); + + if (c > 0) { + buffer.position(buffer.position() + c); + } + + return c; + } + public int read() throws IOException { char[] buffer = new char[1]; int c = read(buffer); diff --git a/classpath/java/lang/Readable.java b/classpath/java/lang/Readable.java new file mode 100644 index 0000000000..b6347c61fe --- /dev/null +++ b/classpath/java/lang/Readable.java @@ -0,0 +1,18 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +import java.nio.CharBuffer; +import java.io.IOException; + +public interface Readable { + int read(CharBuffer buffer) throws IOException; +} diff --git a/classpath/java/net/BindException.java b/classpath/java/net/BindException.java new file mode 100644 index 0000000000..8c171c2881 --- /dev/null +++ b/classpath/java/net/BindException.java @@ -0,0 +1,21 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.net; + +public class BindException extends SocketException { + public BindException(String message) { + super(message); + } + + public BindException() { + this(null); + } +} diff --git a/classpath/java/net/InetAddress.java b/classpath/java/net/InetAddress.java index 39a4aa3dc5..1f3bc18473 100644 --- a/classpath/java/net/InetAddress.java +++ b/classpath/java/net/InetAddress.java @@ -62,9 +62,17 @@ public class InetAddress { (int)((addr[3] + 256) % 256); } - int getRawAddress() { + public int getRawAddress() { return ip; } - static native int ipv4AddressForName(String name); + static native int ipv4AddressForName(String name) throws UnknownHostException; + + public boolean equals(Object o) { + return o instanceof InetAddress && ((InetAddress) o).ip == ip; + } + + public int hashCode() { + return ip; + } } diff --git a/classpath/java/net/InetSocketAddress.java b/classpath/java/net/InetSocketAddress.java index ea8151aa1e..2d8bde788a 100644 --- a/classpath/java/net/InetSocketAddress.java +++ b/classpath/java/net/InetSocketAddress.java @@ -11,15 +11,25 @@ package java.net; public class InetSocketAddress extends SocketAddress { + private final String host; private final InetAddress address; private final int port; - public InetSocketAddress(String host, int port) throws UnknownHostException { - this.address = InetAddress.getByName(host); - this.port = port; + public InetSocketAddress(String host, int port) { + InetAddress address; + try { + address = InetAddress.getByName(host); + host = address.getHostName(); + } catch (UnknownHostException e) { + address = null; + } + this.host = host; + this.address = address; + this.port = port; } public InetSocketAddress(InetAddress address, int port) { + this.host = address.getHostName(); this.address = address; this.port = port; } @@ -29,10 +39,27 @@ public class InetSocketAddress extends SocketAddress { } public String getHostName() { - return address.getHostName(); + return host; } public int getPort() { return port; } + + public boolean equals(Object o) { + if (o instanceof InetSocketAddress) { + InetSocketAddress a = (InetSocketAddress) o; + return a.address.equals(address) && a.port == port; + } else { + return false; + } + } + + public int hashCode() { + return port ^ address.hashCode(); + } + + public String toString() { + return getHostName() + ":" + port; + } } diff --git a/classpath/java/net/Socket.java b/classpath/java/net/Socket.java index 166add6dca..e85d375918 100644 --- a/classpath/java/net/Socket.java +++ b/classpath/java/net/Socket.java @@ -191,6 +191,9 @@ public class Socket implements Closeable, AutoCloseable { outputStream.close(); } + public SocketAddress getRemoteSocketAddress() { + throw new UnsupportedOperationException(); + } @Override protected void finalize() throws Throwable { diff --git a/classpath/java/nio/ArrayByteBuffer.java b/classpath/java/nio/ArrayByteBuffer.java index 90fd92729c..926063c6ff 100644 --- a/classpath/java/nio/ArrayByteBuffer.java +++ b/classpath/java/nio/ArrayByteBuffer.java @@ -54,14 +54,14 @@ class ArrayByteBuffer extends ByteBuffer { public ByteBuffer put(ByteBuffer src) { int length = src.remaining(); - checkPut(position, length); + checkPut(position, length, false); src.get(array, arrayOffset + position, length); position += length; return this; } public ByteBuffer put(byte[] src, int offset, int length) { - checkPut(position, length); + checkPut(position, length, false); System.arraycopy(src, offset, array, arrayOffset + position, length); position += length; @@ -70,7 +70,7 @@ class ArrayByteBuffer extends ByteBuffer { } public ByteBuffer get(byte[] dst, int offset, int length) { - checkGet(position, length); + checkGet(position, length, false); System.arraycopy(array, arrayOffset + position, dst, offset, length); position += length; diff --git a/classpath/java/nio/ArrayCharBuffer.java b/classpath/java/nio/ArrayCharBuffer.java new file mode 100644 index 0000000000..877a1c399b --- /dev/null +++ b/classpath/java/nio/ArrayCharBuffer.java @@ -0,0 +1,92 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.nio; + +class ArrayCharBuffer extends CharBuffer { + private final char[] array; + private final int arrayOffset; + + ArrayCharBuffer(char[] array, int offset, int length, boolean readOnly) { + super(readOnly); + + this.array = array; + this.arrayOffset = offset; + this.capacity = length; + this.limit = length; + this.position = 0; + } + + public CharBuffer asReadOnlyBuffer() { + CharBuffer b = new ArrayCharBuffer(array, arrayOffset, capacity, true); + b.position(position()); + b.limit(limit()); + return b; + } + + public boolean hasArray() { + return true; + } + + public char[] array() { + return array; + } + + public CharBuffer slice() { + return new ArrayCharBuffer + (array, arrayOffset + position, remaining(), true); + } + + public int arrayOffset() { + return arrayOffset; + } + + protected void doPut(int position, char val) { + array[arrayOffset + position] = val; + } + + public CharBuffer put(CharBuffer src) { + int length = src.remaining(); + checkPut(position, length, false); + src.get(array, arrayOffset + position, length); + position += length; + return this; + } + + public CharBuffer put(char[] src, int offset, int length) { + checkPut(position, length, false); + + System.arraycopy(src, offset, array, arrayOffset + position, length); + position += length; + + return this; + } + + public CharBuffer get(char[] dst, int offset, int length) { + checkGet(position, length, false); + + System.arraycopy(array, arrayOffset + position, dst, offset, length); + position += length; + + return this; + } + + protected char doGet(int position) { + return array[arrayOffset+position]; + } + + public String toString() { + return "(ArrayCharBuffer with array: " + array + + " arrayOffset: " + arrayOffset + + " position: " + position + + " limit: " + limit + + " capacity: " + capacity + ")"; + } +} diff --git a/classpath/java/nio/BufferOverflowException.java b/classpath/java/nio/BufferOverflowException.java new file mode 100644 index 0000000000..f19610ac95 --- /dev/null +++ b/classpath/java/nio/BufferOverflowException.java @@ -0,0 +1,14 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.nio; + +public class BufferOverflowException extends RuntimeException { +} diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java index ee3767f7de..0222881136 100644 --- a/classpath/java/nio/ByteBuffer.java +++ b/classpath/java/nio/ByteBuffer.java @@ -69,7 +69,7 @@ public abstract class ByteBuffer public ByteBuffer put(ByteBuffer src) { if (src.hasArray()) { - checkPut(position, src.remaining()); + checkPut(position, src.remaining(), false); put(src.array(), src.arrayOffset() + src.position, src.remaining()); src.position(src.position() + src.remaining()); @@ -107,13 +107,14 @@ public abstract class ByteBuffer } public ByteBuffer put(int offset, byte val) { - checkPut(offset, 1); + checkPut(offset, 1, true); doPut(offset, val); return this; } public ByteBuffer put(byte val) { - put(position, val); + checkPut(position, 1, false); + doPut(position, val); ++ position; return this; } @@ -122,9 +123,7 @@ public abstract class ByteBuffer return put(arr, 0, arr.length); } - public ByteBuffer putLong(int position, long val) { - checkPut(position, 8); - + private void rawPutLong(int position, long val) { doPut(position , (byte) ((val >> 56) & 0xff)); doPut(position + 1, (byte) ((val >> 48) & 0xff)); doPut(position + 2, (byte) ((val >> 40) & 0xff)); @@ -133,54 +132,75 @@ public abstract class ByteBuffer doPut(position + 5, (byte) ((val >> 16) & 0xff)); doPut(position + 6, (byte) ((val >> 8) & 0xff)); doPut(position + 7, (byte) ((val ) & 0xff)); - - return this; } - public ByteBuffer putInt(int position, int val) { - checkPut(position, 4); - + private void rawPutInt(int position, int val) { doPut(position , (byte) ((val >> 24) & 0xff)); doPut(position + 1, (byte) ((val >> 16) & 0xff)); doPut(position + 2, (byte) ((val >> 8) & 0xff)); doPut(position + 3, (byte) ((val ) & 0xff)); + } + + private void rawPutShort(int position, short val) { + doPut(position , (byte) ((val >> 8) & 0xff)); + doPut(position + 1, (byte) ((val ) & 0xff)); + } + + public ByteBuffer putLong(int position, long val) { + checkPut(position, 8, true); + + rawPutLong(position, val); + + return this; + } + + public ByteBuffer putInt(int position, int val) { + checkPut(position, 4, true); + + rawPutInt(position, val); return this; } public ByteBuffer putShort(int position, short val) { - checkPut(position, 2); + checkPut(position, 2, true); - doPut(position , (byte) ((val >> 8) & 0xff)); - doPut(position + 1, (byte) ((val ) & 0xff)); + rawPutShort(position, val); return this; } public ByteBuffer putLong(long val) { - putLong(position, val); + checkPut(position, 8, false); + + rawPutLong(position, val); position += 8; return this; } public ByteBuffer putInt(int val) { - putInt(position, val); + checkPut(position, 4, false); + + rawPutInt(position, val); position += 4; return this; } public ByteBuffer putShort(short val) { - putShort(position, val); + checkPut(position, 2, false); + + rawPutShort(position, val); position += 2; return this; } public byte get() { - return get(position++); + checkGet(position, 1, false); + return doGet(position++); } public byte get(int position) { - checkGet(position, 1); + checkGet(position, 1, true); return doGet(position); } @@ -189,8 +209,24 @@ public abstract class ByteBuffer } public long getLong(int position) { - checkGet(position, 8); + checkGet(position, 8, true); + return rawGetLong(position); + } + + public int getInt(int position) { + checkGet(position, 4, true); + + return rawGetInt(position); + } + + public short getShort(int position) { + checkGet(position, 2, true); + + return rawGetShort(position); + } + + private long rawGetLong(int position) { return (((long) (doGet(position ) & 0xFF)) << 56) | (((long) (doGet(position + 1) & 0xFF)) << 48) | (((long) (doGet(position + 2) & 0xFF)) << 40) @@ -201,48 +237,60 @@ public abstract class ByteBuffer | (((long) (doGet(position + 7) & 0xFF)) ); } - public int getInt(int position) { - checkGet(position, 4); - + private int rawGetInt(int position) { return (((int) (doGet(position ) & 0xFF)) << 24) | (((int) (doGet(position + 1) & 0xFF)) << 16) | (((int) (doGet(position + 2) & 0xFF)) << 8) | (((int) (doGet(position + 3) & 0xFF)) ); } - public short getShort(int position) { - checkGet(position, 2); - + private short rawGetShort(int position) { return (short) (( ((int) (doGet(position ) & 0xFF)) << 8) | (((int) (doGet(position + 1) & 0xFF)) )); } public long getLong() { - long r = getLong(position); + checkGet(position, 8, false); + + long r = rawGetLong(position); position += 8; return r; } public int getInt() { - int r = getInt(position); + checkGet(position, 4, false); + + int r = rawGetInt(position); position += 4; return r; } public short getShort() { - short r = getShort(position); + checkGet(position, 2, false); + + short r = rawGetShort(position); position += 2; return r; } - protected void checkPut(int position, int amount) { - if (readOnly) throw new ReadOnlyBufferException(); - if (position < 0 || position+amount > limit) - throw new IndexOutOfBoundsException(); + protected void checkPut(int position, int amount, boolean absolute) { + if (readOnly) { + throw new ReadOnlyBufferException(); + } + + if (position < 0 || position+amount > limit) { + throw absolute + ? new IndexOutOfBoundsException() + : new BufferOverflowException(); + } } - protected void checkGet(int position, int amount) { - if (amount > limit-position) throw new IndexOutOfBoundsException(); + protected void checkGet(int position, int amount, boolean absolute) { + if (amount > limit-position) { + throw absolute + ? new IndexOutOfBoundsException() + : new BufferUnderflowException(); + } } public ByteBuffer order(ByteOrder order) { diff --git a/classpath/java/nio/CharBuffer.java b/classpath/java/nio/CharBuffer.java new file mode 100644 index 0000000000..84bbda0b9e --- /dev/null +++ b/classpath/java/nio/CharBuffer.java @@ -0,0 +1,154 @@ +/* Copyright (c) 2008-2014, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.nio; + +public abstract class CharBuffer + extends Buffer + implements Comparable +{ + private final boolean readOnly; + + protected CharBuffer(boolean readOnly) { + this.readOnly = readOnly; + } + + public static CharBuffer allocate(int capacity) { + return new ArrayCharBuffer(new char[capacity], 0, capacity, false); + } + + public static CharBuffer wrap(char[] array) { + return wrap(array, 0, array.length); + } + + public static CharBuffer wrap(char[] array, int offset, int length) { + return new ArrayCharBuffer(array, offset, length, false); + } + + public abstract CharBuffer asReadOnlyBuffer(); + + public abstract CharBuffer slice(); + + protected abstract void doPut(int offset, char value); + + public abstract CharBuffer put(char[] src, int offset, int length); + + protected abstract char doGet(int offset); + + public abstract CharBuffer get(char[] dst, int offset, int length); + + public boolean hasArray() { + return false; + } + + public CharBuffer compact() { + int remaining = remaining(); + + if (position != 0) { + CharBuffer b = slice(); + position = 0; + put(b); + } + + position = remaining; + limit(capacity()); + + return this; + } + + public CharBuffer put(CharBuffer src) { + if (src.hasArray()) { + checkPut(position, src.remaining(), false); + + put(src.array(), src.arrayOffset() + src.position, src.remaining()); + src.position(src.position() + src.remaining()); + + return this; + } else { + char[] buffer = new char[src.remaining()]; + src.get(buffer); + return put(buffer); + } + } + + public int compareTo(CharBuffer o) { + int end = (remaining() < o.remaining() ? remaining() : o.remaining()); + + for (int i = 0; i < end; ++i) { + int d = get(position + i) - o.get(o.position + i); + if (d != 0) { + return d; + } + } + return remaining() - o.remaining(); + } + + public boolean equals(Object o) { + return o instanceof CharBuffer && compareTo((CharBuffer) o) == 0; + } + + public char[] array() { + throw new UnsupportedOperationException(); + } + + public int arrayOffset() { + throw new UnsupportedOperationException(); + } + + public CharBuffer put(int offset, char val) { + checkPut(offset, 1, true); + doPut(offset, val); + return this; + } + + public CharBuffer put(char val) { + put(position, val); + ++ position; + return this; + } + + public CharBuffer put(char[] arr) { + return put(arr, 0, arr.length); + } + + public char get() { + checkGet(position, 1, false); + return doGet(position++); + } + + public char get(int position) { + checkGet(position, 1, true); + return doGet(position); + } + + public CharBuffer get(char[] dst) { + return get(dst, 0, dst.length); + } + + protected void checkPut(int position, int amount, boolean absolute) { + if (readOnly) { + throw new ReadOnlyBufferException(); + } + + if (position < 0 || position+amount > limit) { + throw absolute + ? new IndexOutOfBoundsException() + : new BufferOverflowException(); + } + } + + protected void checkGet(int position, int amount, boolean absolute) { + if (amount > limit-position) { + throw absolute + ? new IndexOutOfBoundsException() + : new BufferUnderflowException(); + } + } +} diff --git a/classpath/java/nio/DirectByteBuffer.java b/classpath/java/nio/DirectByteBuffer.java index 8c9c5ffe39..8351f8f108 100644 --- a/classpath/java/nio/DirectByteBuffer.java +++ b/classpath/java/nio/DirectByteBuffer.java @@ -48,7 +48,7 @@ class DirectByteBuffer extends ByteBuffer { public ByteBuffer put(ByteBuffer src) { if (src instanceof DirectByteBuffer) { - checkPut(position, src.remaining()); + checkPut(position, src.remaining(), false); DirectByteBuffer b = (DirectByteBuffer) src; @@ -69,7 +69,7 @@ class DirectByteBuffer extends ByteBuffer { throw new ArrayIndexOutOfBoundsException(); } - checkPut(position, length); + checkPut(position, length, false); unsafe.copyMemory (src, baseOffset + offset, null, address + position, length); @@ -84,7 +84,7 @@ class DirectByteBuffer extends ByteBuffer { throw new ArrayIndexOutOfBoundsException(); } - checkGet(position, length); + checkGet(position, length, false); unsafe.copyMemory (null, address + position, dst, baseOffset + offset, length); diff --git a/classpath/java/nio/channels/DatagramChannel.java b/classpath/java/nio/channels/DatagramChannel.java index 399e09decb..37ae873446 100644 --- a/classpath/java/nio/channels/DatagramChannel.java +++ b/classpath/java/nio/channels/DatagramChannel.java @@ -26,7 +26,7 @@ public class DatagramChannel extends SelectableChannel { public static final int InvalidSocket = -1; - private int socket = InvalidSocket; + private int socket = makeSocket(); private boolean blocking = true; private boolean connected = false; @@ -80,8 +80,12 @@ public class DatagramChannel extends SelectableChannel throw new UnsupportedAddressTypeException(); } - socket = bind(inetAddress.getHostName(), inetAddress.getPort()); - configureBlocking(); + if (inetAddress == null) { + bind(socket, 0, 0); + } else { + bind(socket, inetAddress.getAddress().getRawAddress(), + inetAddress.getPort()); + } return this; } @@ -94,10 +98,8 @@ public class DatagramChannel extends SelectableChannel throw new UnsupportedAddressTypeException(); } - socket = connect(inetAddress.getHostName(), inetAddress.getPort()); - configureBlocking(); - - if (socket != 0) connected = true; + connected = connect(socket, inetAddress.getAddress().getRawAddress(), + inetAddress.getPort()); return this; } @@ -145,6 +147,31 @@ public class DatagramChannel extends SelectableChannel } } + public int send(ByteBuffer b, SocketAddress address) throws IOException { + if (b.remaining() == 0) return 0; + + InetSocketAddress inetAddress; + try { + inetAddress = (InetSocketAddress) address; + } catch (ClassCastException e) { + throw new UnsupportedAddressTypeException(); + } + + byte[] array = b.array(); + if (array == null) throw new NullPointerException(); + + int c = send + (socket, inetAddress.getAddress().getRawAddress(), + inetAddress.getPort(), array, b.arrayOffset() + b.position(), + b.remaining(), blocking); + + if (c > 0) { + b.position(b.position() + c); + } + + return c; + } + private static String ipv4ToString(int address) { StringBuilder sb = new StringBuilder(); @@ -178,22 +205,35 @@ public class DatagramChannel extends SelectableChannel /** TODO: This is probably incomplete. */ public DatagramChannel disconnect() throws IOException { - close(); + connect(socket, 0, 0); connected = false; return this; } + public void close() throws IOException { + if (isOpen()) { + super.close(); + close(socket); + } + } + + private static native int makeSocket(); private static native void configureBlocking(int socket, boolean blocking) throws IOException; - private static native int bind(String hostname, int port) + private static native void bind(int socket, int host, int port) throws IOException; - private static native int connect(String hostname, int port) + private static native boolean connect(int socket, int host, int port) throws IOException; private static native int write(int socket, byte[] array, int offset, int length, boolean blocking) throws IOException; + private static native int send(int socket, int host, int port, + byte[] array, int offset, + int length, boolean blocking) + throws IOException; private static native int receive(int socket, byte[] array, int offset, int length, boolean blocking, int[] address) throws IOException; + private static native void close(int socket); } diff --git a/classpath/java/nio/channels/ServerSocketChannel.java b/classpath/java/nio/channels/ServerSocketChannel.java index 953395a81e..68ba0f8854 100644 --- a/classpath/java/nio/channels/ServerSocketChannel.java +++ b/classpath/java/nio/channels/ServerSocketChannel.java @@ -66,10 +66,10 @@ public class ServerSocketChannel extends SelectableChannel { } } - private int doListen(String host, int port) throws IOException { + private void doListen(int socket, int host, int port) throws IOException { Socket.init(); - return natDoListen(host, port); + natDoListen(socket, host, port); } public class Handle extends ServerSocket { @@ -82,11 +82,10 @@ public class ServerSocketChannel extends SelectableChannel { } catch (ClassCastException e) { throw new IllegalArgumentException(); } - channel.socket = doListen(a.getHostName(), a.getPort()); - channel.configureBlocking(channel.isBlocking()); + doListen(channel.socket, a.getAddress().getRawAddress(), a.getPort()); } } private static native int natDoAccept(int socket) throws IOException; - private static native int natDoListen(String host, int port) throws IOException; + private static native void natDoListen(int socket, int host, int port) throws IOException; } diff --git a/classpath/java/nio/channels/SocketChannel.java b/classpath/java/nio/channels/SocketChannel.java index 966a4f0c57..fd3cd2b36b 100644 --- a/classpath/java/nio/channels/SocketChannel.java +++ b/classpath/java/nio/channels/SocketChannel.java @@ -22,7 +22,7 @@ public class SocketChannel extends SelectableChannel { public static final int InvalidSocket = -1; - int socket = InvalidSocket; + int socket = makeSocket(); boolean connected = false; boolean readyToConnect = false; boolean blocking = true; @@ -64,7 +64,7 @@ public class SocketChannel extends SelectableChannel } catch (ClassCastException e) { throw new UnsupportedAddressTypeException(); } - socket = doConnect(a.getHostName(), a.getPort()); + doConnect(socket, a.getAddress().getRawAddress(), a.getPort()); configureBlocking(blocking); return connected; } @@ -98,13 +98,10 @@ public class SocketChannel extends SelectableChannel } } - private int doConnect(String host, int port) throws IOException { - if (host == null) throw new NullPointerException(); - - boolean b[] = new boolean[1]; - int s = natDoConnect(host, port, blocking, b); - connected = b[0]; - return s; + private void doConnect(int socket, int host, int port) + throws IOException + { + connected = natDoConnect(socket, host, port); } public int read(ByteBuffer b) throws IOException { @@ -170,21 +167,40 @@ public class SocketChannel extends SelectableChannel public class Handle extends Socket { public Handle() throws IOException { - super(); - } + super(); + } - public void setTcpNoDelay(boolean on) throws SocketException { + public void setTcpNoDelay(boolean on) throws SocketException { natSetTcpNoDelay(socket, on); } + + public void bind(SocketAddress address) + throws IOException + { + InetSocketAddress a; + try { + a = (InetSocketAddress) address; + } catch (ClassCastException e) { + throw new IllegalArgumentException(); + } + + if (a == null) { + bind(socket, 0, 0); + } else { + bind(socket, a.getAddress().getRawAddress(), a.getPort()); + } + } } + private static native int makeSocket(); private static native void configureBlocking(int socket, boolean blocking) throws IOException; private static native void natSetTcpNoDelay(int socket, boolean on) throws SocketException; - - private static native int natDoConnect(String host, int port, boolean blocking, boolean[] connected) + private static native void bind(int socket, int host, int port) + throws IOException; + private static native boolean natDoConnect(int socket, int host, int port) throws IOException; private static native void natFinishConnect(int socket) throws IOException; diff --git a/test/Buffers.java b/test/Buffers.java index 804d81eb93..3704ae8dd7 100644 --- a/test/Buffers.java +++ b/test/Buffers.java @@ -1,4 +1,6 @@ import java.nio.ByteBuffer; +import java.nio.BufferUnderflowException; +import java.nio.BufferOverflowException; public class Buffers { static { @@ -57,7 +59,7 @@ public class Buffers { private static native void freeNative(ByteBuffer b); - public static void main(String[] args) { + public static void main(String[] args) throws Exception { Factory array = new Factory() { public ByteBuffer allocate(int capacity) { return ByteBuffer.allocate(capacity); @@ -99,6 +101,34 @@ public class Buffers { test(native_, array); test(native_, direct); test(native_, native_); + + try { + ByteBuffer.allocate(1).getInt(); + expect(false); + } catch (BufferUnderflowException e) { + // cool + } + + try { + ByteBuffer.allocate(1).getInt(0); + expect(false); + } catch (IndexOutOfBoundsException e) { + // cool + } + + try { + ByteBuffer.allocate(1).putInt(1); + expect(false); + } catch (BufferOverflowException e) { + // cool + } + + try { + ByteBuffer.allocate(1).putInt(0, 1); + expect(false); + } catch (IndexOutOfBoundsException e) { + // cool + } } private interface Factory { diff --git a/test/Datagrams.java b/test/Datagrams.java index 3e017261da..d5dcd88d07 100644 --- a/test/Datagrams.java +++ b/test/Datagrams.java @@ -22,20 +22,28 @@ public class Datagrams { } public static void main(String[] args) throws Exception { + test(true); + test(false); + } + + private static void test(boolean send) throws Exception { final String Hostname = "localhost"; - final int Port = 22043; - final SocketAddress Address = new InetSocketAddress(Hostname, Port); + final int InPort = 22043; + final int OutPort = 22044; + final SocketAddress InAddress = new InetSocketAddress(Hostname, InPort); + final SocketAddress OutAddress = new InetSocketAddress(Hostname, OutPort); final byte[] Message = "hello, world!".getBytes(); DatagramChannel out = DatagramChannel.open(); try { out.configureBlocking(false); - out.connect(Address); + out.socket().bind(OutAddress); + if (! send) out.connect(InAddress); DatagramChannel in = DatagramChannel.open(); try { in.configureBlocking(false); - in.socket().bind(Address); + in.socket().bind(InAddress); Selector selector = Selector.open(); try { @@ -53,14 +61,18 @@ public class Datagrams { switch (state) { case 0: { if (outKey.isWritable()) { - out.write(ByteBuffer.wrap(Message)); + if (send) { + out.send(ByteBuffer.wrap(Message), InAddress); + } else { + out.write(ByteBuffer.wrap(Message)); + } state = 1; } } break; case 1: { if (inKey.isReadable()) { - in.receive(inBuffer); + expect(in.receive(inBuffer).equals(OutAddress)); if (! inBuffer.hasRemaining()) { expect(equal(inBuffer.array(), inBuffer.arrayOffset(), diff --git a/test/Strings.java b/test/Strings.java index 76815af535..f37c99efaa 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -206,5 +206,12 @@ public class Strings { expect("abc".lastIndexOf('b', 100) == 1); testTrivialPattern(); + + { String s = "hello, world!"; + java.nio.CharBuffer buffer = java.nio.CharBuffer.allocate(s.length()); + new java.io.InputStreamReader + (new java.io.ByteArrayInputStream(s.getBytes())).read(buffer); + expect(s.equals(new String(buffer.array()))); + } } }