mirror of
https://github.com/corda/corda.git
synced 2025-01-19 11:16:54 +00:00
various refinements to network implementation
The main idea is to make DatagramChannel and *SocketChannel behave in a way that more closely matches the standard, e.g. allow binding sockets to addresses without necessarily listening on those addresses and accept null addresses where appropriate. It also avoids multiple redundant DNS lookups. This commit also implements CharBuffer and BindException, and adds the Readable interface.
This commit is contained in:
parent
1e1fff58f8
commit
6e7149061c
@ -149,46 +149,12 @@ throwSocketException(JNIEnv* e)
|
|||||||
throwSocketException(e, errorString(e));
|
throwSocketException(e, errorString(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void init(sockaddr_in* address, jint host, jint port)
|
||||||
init(JNIEnv* e, sockaddr_in* address, jstring hostString, jint port)
|
|
||||||
{
|
{
|
||||||
const char* chars = e->GetStringUTFChars(hostString, 0);
|
memset(address, 0, sizeof(sockaddr_in));
|
||||||
if (chars) {
|
address->sin_family = AF_INET;
|
||||||
#ifdef PLATFORM_WINDOWS
|
address->sin_port = htons(port);
|
||||||
hostent* host = gethostbyname(chars);
|
address->sin_addr.s_addr = htonl(host);
|
||||||
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<in_addr*>(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<sockaddr_in*>
|
|
||||||
(result->ai_addr)->sin_addr;
|
|
||||||
|
|
||||||
freeaddrinfo(result);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
@ -384,8 +350,17 @@ doWrite(int fd, const void* buffer, size_t count)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int doSend(int fd, sockaddr_in* address, const void* buffer, size_t count)
|
||||||
makeSocket(JNIEnv* e, int type = SOCK_STREAM, int protocol = IPPROTO_TCP)
|
{
|
||||||
|
return sendto(fd,
|
||||||
|
static_cast<const char*>(buffer),
|
||||||
|
count,
|
||||||
|
0,
|
||||||
|
reinterpret_cast<sockaddr*>(address),
|
||||||
|
sizeof(sockaddr_in));
|
||||||
|
}
|
||||||
|
|
||||||
|
int makeSocket(JNIEnv* e, int type = SOCK_STREAM, int protocol = IPPROTO_TCP)
|
||||||
{
|
{
|
||||||
int s = ::socket(AF_INET, type, protocol);
|
int s = ::socket(AF_INET, type, protocol);
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
@ -405,43 +380,44 @@ Java_java_nio_channels_ServerSocketChannel_natDoAccept(JNIEnv *e, jclass, jint s
|
|||||||
return ::doAccept(e, socket);
|
return ::doAccept(e, socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv *e,
|
Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv* e,
|
||||||
jclass,
|
jclass,
|
||||||
jstring host,
|
jint socket,
|
||||||
jint port)
|
jint host,
|
||||||
|
jint port)
|
||||||
{
|
{
|
||||||
int s = makeSocket(e);
|
|
||||||
if (s < 0) return s;
|
|
||||||
if (e->ExceptionCheck()) return 0;
|
|
||||||
|
|
||||||
sockaddr_in address;
|
sockaddr_in address;
|
||||||
init(e, &address, host, port);
|
init(&address, host, port);
|
||||||
if (e->ExceptionCheck()) return 0;
|
|
||||||
|
|
||||||
::doBind(e, s, &address);
|
::doBind(e, socket, &address);
|
||||||
if (e->ExceptionCheck()) return 0;
|
if (e->ExceptionCheck())
|
||||||
|
return;
|
||||||
|
|
||||||
::doListen(e, s);
|
::doListen(e, socket);
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_java_nio_channels_DatagramChannel_bind(JNIEnv *e,
|
Java_java_nio_channels_SocketChannel_bind(JNIEnv* e,
|
||||||
jclass,
|
jclass,
|
||||||
jstring host,
|
jint socket,
|
||||||
jint port)
|
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;
|
sockaddr_in address;
|
||||||
init(e, &address, host, port);
|
init(&address, host, port);
|
||||||
if (e->ExceptionCheck()) return 0;
|
|
||||||
|
|
||||||
::doBind(e, s, &address);
|
::doBind(e, socket, &address);
|
||||||
return s;
|
}
|
||||||
|
|
||||||
|
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
|
extern "C" JNIEXPORT void JNICALL
|
||||||
@ -472,45 +448,42 @@ Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e,
|
|||||||
setTcpNoDelay(e, socket, on);
|
setTcpNoDelay(e, socket, on);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jboolean JNICALL
|
||||||
Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e,
|
Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv* e,
|
||||||
jclass,
|
jclass,
|
||||||
jstring host,
|
jint socket,
|
||||||
jint port,
|
jint host,
|
||||||
jboolean blocking,
|
jint port)
|
||||||
jbooleanArray retVal)
|
|
||||||
{
|
{
|
||||||
int s = makeSocket(e);
|
|
||||||
if (e->ExceptionCheck()) return 0;
|
|
||||||
|
|
||||||
setBlocking(e, s, blocking);
|
|
||||||
|
|
||||||
sockaddr_in address;
|
sockaddr_in address;
|
||||||
init(e, &address, host, port);
|
init(&address, host, port);
|
||||||
if (e->ExceptionCheck()) return 0;
|
|
||||||
|
return ::doConnect(e, socket, &address);
|
||||||
jboolean connected = ::doConnect(e, s, &address);
|
|
||||||
e->SetBooleanArrayRegion(retVal, 0, 1, &connected);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
Java_java_nio_channels_DatagramChannel_connect(JNIEnv *e,
|
Java_java_nio_channels_SocketChannel_makeSocket(JNIEnv* e, jclass)
|
||||||
jclass,
|
|
||||||
jstring host,
|
|
||||||
jint port)
|
|
||||||
{
|
{
|
||||||
int s = makeSocket(e, SOCK_DGRAM, IPPROTO_UDP);
|
return makeSocket(e);
|
||||||
if (e->ExceptionCheck()) return 0;
|
}
|
||||||
|
|
||||||
|
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;
|
sockaddr_in address;
|
||||||
init(e, &address, host, port);
|
init(&address, host, port);
|
||||||
if (e->ExceptionCheck()) return 0;
|
|
||||||
|
return ::doConnect(e, socket, &address);
|
||||||
::doConnect(e, s, &address);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
@ -669,6 +642,51 @@ Java_java_nio_channels_DatagramChannel_write(JNIEnv* e,
|
|||||||
(e, c, socket, buffer, offset, length, blocking);
|
(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<uint8_t*>(allocate(e, length));
|
||||||
|
if (buf) {
|
||||||
|
e->GetByteArrayRegion(
|
||||||
|
buffer, offset, length, reinterpret_cast<jbyte*>(buf));
|
||||||
|
r = ::doSend(socket, &address, buf, length);
|
||||||
|
free(buf);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jboolean isCopy;
|
||||||
|
uint8_t* buf
|
||||||
|
= static_cast<uint8_t*>(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
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e,
|
Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e,
|
||||||
jclass,
|
jclass,
|
||||||
@ -693,6 +711,14 @@ Java_java_nio_channels_SocketChannel_natCloseSocket(JNIEnv *,
|
|||||||
doClose(socket);
|
doClose(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_nio_channels_DatagramChannel_close(JNIEnv *,
|
||||||
|
jclass,
|
||||||
|
jint socket)
|
||||||
|
{
|
||||||
|
doClose(socket);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class Pipe {
|
class Pipe {
|
||||||
|
@ -10,7 +10,21 @@
|
|||||||
|
|
||||||
package java.io;
|
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 {
|
public int read() throws IOException {
|
||||||
char[] buffer = new char[1];
|
char[] buffer = new char[1];
|
||||||
int c = read(buffer);
|
int c = read(buffer);
|
||||||
|
18
classpath/java/lang/Readable.java
Normal file
18
classpath/java/lang/Readable.java
Normal file
@ -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;
|
||||||
|
}
|
21
classpath/java/net/BindException.java
Normal file
21
classpath/java/net/BindException.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -62,9 +62,17 @@ public class InetAddress {
|
|||||||
(int)((addr[3] + 256) % 256);
|
(int)((addr[3] + 256) % 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getRawAddress() {
|
public int getRawAddress() {
|
||||||
return ip;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,25 @@
|
|||||||
package java.net;
|
package java.net;
|
||||||
|
|
||||||
public class InetSocketAddress extends SocketAddress {
|
public class InetSocketAddress extends SocketAddress {
|
||||||
|
private final String host;
|
||||||
private final InetAddress address;
|
private final InetAddress address;
|
||||||
private final int port;
|
private final int port;
|
||||||
|
|
||||||
public InetSocketAddress(String host, int port) throws UnknownHostException {
|
public InetSocketAddress(String host, int port) {
|
||||||
this.address = InetAddress.getByName(host);
|
InetAddress address;
|
||||||
this.port = port;
|
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) {
|
public InetSocketAddress(InetAddress address, int port) {
|
||||||
|
this.host = address.getHostName();
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
@ -29,10 +39,27 @@ public class InetSocketAddress extends SocketAddress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getHostName() {
|
public String getHostName() {
|
||||||
return address.getHostName();
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
return port;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,6 +191,9 @@ public class Socket implements Closeable, AutoCloseable {
|
|||||||
outputStream.close();
|
outputStream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SocketAddress getRemoteSocketAddress() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void finalize() throws Throwable {
|
protected void finalize() throws Throwable {
|
||||||
|
@ -54,14 +54,14 @@ class ArrayByteBuffer extends ByteBuffer {
|
|||||||
|
|
||||||
public ByteBuffer put(ByteBuffer src) {
|
public ByteBuffer put(ByteBuffer src) {
|
||||||
int length = src.remaining();
|
int length = src.remaining();
|
||||||
checkPut(position, length);
|
checkPut(position, length, false);
|
||||||
src.get(array, arrayOffset + position, length);
|
src.get(array, arrayOffset + position, length);
|
||||||
position += length;
|
position += length;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer put(byte[] src, int offset, int length) {
|
public ByteBuffer put(byte[] src, int offset, int length) {
|
||||||
checkPut(position, length);
|
checkPut(position, length, false);
|
||||||
|
|
||||||
System.arraycopy(src, offset, array, arrayOffset + position, length);
|
System.arraycopy(src, offset, array, arrayOffset + position, length);
|
||||||
position += length;
|
position += length;
|
||||||
@ -70,7 +70,7 @@ class ArrayByteBuffer extends ByteBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer get(byte[] dst, int offset, int length) {
|
public ByteBuffer get(byte[] dst, int offset, int length) {
|
||||||
checkGet(position, length);
|
checkGet(position, length, false);
|
||||||
|
|
||||||
System.arraycopy(array, arrayOffset + position, dst, offset, length);
|
System.arraycopy(array, arrayOffset + position, dst, offset, length);
|
||||||
position += length;
|
position += length;
|
||||||
|
92
classpath/java/nio/ArrayCharBuffer.java
Normal file
92
classpath/java/nio/ArrayCharBuffer.java
Normal file
@ -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 + ")";
|
||||||
|
}
|
||||||
|
}
|
14
classpath/java/nio/BufferOverflowException.java
Normal file
14
classpath/java/nio/BufferOverflowException.java
Normal file
@ -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 {
|
||||||
|
}
|
@ -69,7 +69,7 @@ public abstract class ByteBuffer
|
|||||||
|
|
||||||
public ByteBuffer put(ByteBuffer src) {
|
public ByteBuffer put(ByteBuffer src) {
|
||||||
if (src.hasArray()) {
|
if (src.hasArray()) {
|
||||||
checkPut(position, src.remaining());
|
checkPut(position, src.remaining(), false);
|
||||||
|
|
||||||
put(src.array(), src.arrayOffset() + src.position, src.remaining());
|
put(src.array(), src.arrayOffset() + src.position, src.remaining());
|
||||||
src.position(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) {
|
public ByteBuffer put(int offset, byte val) {
|
||||||
checkPut(offset, 1);
|
checkPut(offset, 1, true);
|
||||||
doPut(offset, val);
|
doPut(offset, val);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer put(byte val) {
|
public ByteBuffer put(byte val) {
|
||||||
put(position, val);
|
checkPut(position, 1, false);
|
||||||
|
doPut(position, val);
|
||||||
++ position;
|
++ position;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -122,9 +123,7 @@ public abstract class ByteBuffer
|
|||||||
return put(arr, 0, arr.length);
|
return put(arr, 0, arr.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer putLong(int position, long val) {
|
private void rawPutLong(int position, long val) {
|
||||||
checkPut(position, 8);
|
|
||||||
|
|
||||||
doPut(position , (byte) ((val >> 56) & 0xff));
|
doPut(position , (byte) ((val >> 56) & 0xff));
|
||||||
doPut(position + 1, (byte) ((val >> 48) & 0xff));
|
doPut(position + 1, (byte) ((val >> 48) & 0xff));
|
||||||
doPut(position + 2, (byte) ((val >> 40) & 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 + 5, (byte) ((val >> 16) & 0xff));
|
||||||
doPut(position + 6, (byte) ((val >> 8) & 0xff));
|
doPut(position + 6, (byte) ((val >> 8) & 0xff));
|
||||||
doPut(position + 7, (byte) ((val ) & 0xff));
|
doPut(position + 7, (byte) ((val ) & 0xff));
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer putInt(int position, int val) {
|
private void rawPutInt(int position, int val) {
|
||||||
checkPut(position, 4);
|
|
||||||
|
|
||||||
doPut(position , (byte) ((val >> 24) & 0xff));
|
doPut(position , (byte) ((val >> 24) & 0xff));
|
||||||
doPut(position + 1, (byte) ((val >> 16) & 0xff));
|
doPut(position + 1, (byte) ((val >> 16) & 0xff));
|
||||||
doPut(position + 2, (byte) ((val >> 8) & 0xff));
|
doPut(position + 2, (byte) ((val >> 8) & 0xff));
|
||||||
doPut(position + 3, (byte) ((val ) & 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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer putShort(int position, short val) {
|
public ByteBuffer putShort(int position, short val) {
|
||||||
checkPut(position, 2);
|
checkPut(position, 2, true);
|
||||||
|
|
||||||
doPut(position , (byte) ((val >> 8) & 0xff));
|
rawPutShort(position, val);
|
||||||
doPut(position + 1, (byte) ((val ) & 0xff));
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer putLong(long val) {
|
public ByteBuffer putLong(long val) {
|
||||||
putLong(position, val);
|
checkPut(position, 8, false);
|
||||||
|
|
||||||
|
rawPutLong(position, val);
|
||||||
position += 8;
|
position += 8;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer putInt(int val) {
|
public ByteBuffer putInt(int val) {
|
||||||
putInt(position, val);
|
checkPut(position, 4, false);
|
||||||
|
|
||||||
|
rawPutInt(position, val);
|
||||||
position += 4;
|
position += 4;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer putShort(short val) {
|
public ByteBuffer putShort(short val) {
|
||||||
putShort(position, val);
|
checkPut(position, 2, false);
|
||||||
|
|
||||||
|
rawPutShort(position, val);
|
||||||
position += 2;
|
position += 2;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte get() {
|
public byte get() {
|
||||||
return get(position++);
|
checkGet(position, 1, false);
|
||||||
|
return doGet(position++);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte get(int position) {
|
public byte get(int position) {
|
||||||
checkGet(position, 1);
|
checkGet(position, 1, true);
|
||||||
return doGet(position);
|
return doGet(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,8 +209,24 @@ public abstract class ByteBuffer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getLong(int position) {
|
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)
|
return (((long) (doGet(position ) & 0xFF)) << 56)
|
||||||
| (((long) (doGet(position + 1) & 0xFF)) << 48)
|
| (((long) (doGet(position + 1) & 0xFF)) << 48)
|
||||||
| (((long) (doGet(position + 2) & 0xFF)) << 40)
|
| (((long) (doGet(position + 2) & 0xFF)) << 40)
|
||||||
@ -201,48 +237,60 @@ public abstract class ByteBuffer
|
|||||||
| (((long) (doGet(position + 7) & 0xFF)) );
|
| (((long) (doGet(position + 7) & 0xFF)) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getInt(int position) {
|
private int rawGetInt(int position) {
|
||||||
checkGet(position, 4);
|
|
||||||
|
|
||||||
return (((int) (doGet(position ) & 0xFF)) << 24)
|
return (((int) (doGet(position ) & 0xFF)) << 24)
|
||||||
| (((int) (doGet(position + 1) & 0xFF)) << 16)
|
| (((int) (doGet(position + 1) & 0xFF)) << 16)
|
||||||
| (((int) (doGet(position + 2) & 0xFF)) << 8)
|
| (((int) (doGet(position + 2) & 0xFF)) << 8)
|
||||||
| (((int) (doGet(position + 3) & 0xFF)) );
|
| (((int) (doGet(position + 3) & 0xFF)) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getShort(int position) {
|
private short rawGetShort(int position) {
|
||||||
checkGet(position, 2);
|
|
||||||
|
|
||||||
return (short) (( ((int) (doGet(position ) & 0xFF)) << 8)
|
return (short) (( ((int) (doGet(position ) & 0xFF)) << 8)
|
||||||
| (((int) (doGet(position + 1) & 0xFF)) ));
|
| (((int) (doGet(position + 1) & 0xFF)) ));
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLong() {
|
public long getLong() {
|
||||||
long r = getLong(position);
|
checkGet(position, 8, false);
|
||||||
|
|
||||||
|
long r = rawGetLong(position);
|
||||||
position += 8;
|
position += 8;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getInt() {
|
public int getInt() {
|
||||||
int r = getInt(position);
|
checkGet(position, 4, false);
|
||||||
|
|
||||||
|
int r = rawGetInt(position);
|
||||||
position += 4;
|
position += 4;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getShort() {
|
public short getShort() {
|
||||||
short r = getShort(position);
|
checkGet(position, 2, false);
|
||||||
|
|
||||||
|
short r = rawGetShort(position);
|
||||||
position += 2;
|
position += 2;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkPut(int position, int amount) {
|
protected void checkPut(int position, int amount, boolean absolute) {
|
||||||
if (readOnly) throw new ReadOnlyBufferException();
|
if (readOnly) {
|
||||||
if (position < 0 || position+amount > limit)
|
throw new ReadOnlyBufferException();
|
||||||
throw new IndexOutOfBoundsException();
|
}
|
||||||
|
|
||||||
|
if (position < 0 || position+amount > limit) {
|
||||||
|
throw absolute
|
||||||
|
? new IndexOutOfBoundsException()
|
||||||
|
: new BufferOverflowException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkGet(int position, int amount) {
|
protected void checkGet(int position, int amount, boolean absolute) {
|
||||||
if (amount > limit-position) throw new IndexOutOfBoundsException();
|
if (amount > limit-position) {
|
||||||
|
throw absolute
|
||||||
|
? new IndexOutOfBoundsException()
|
||||||
|
: new BufferUnderflowException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer order(ByteOrder order) {
|
public ByteBuffer order(ByteOrder order) {
|
||||||
|
154
classpath/java/nio/CharBuffer.java
Normal file
154
classpath/java/nio/CharBuffer.java
Normal file
@ -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<CharBuffer>
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -48,7 +48,7 @@ class DirectByteBuffer extends ByteBuffer {
|
|||||||
|
|
||||||
public ByteBuffer put(ByteBuffer src) {
|
public ByteBuffer put(ByteBuffer src) {
|
||||||
if (src instanceof DirectByteBuffer) {
|
if (src instanceof DirectByteBuffer) {
|
||||||
checkPut(position, src.remaining());
|
checkPut(position, src.remaining(), false);
|
||||||
|
|
||||||
DirectByteBuffer b = (DirectByteBuffer) src;
|
DirectByteBuffer b = (DirectByteBuffer) src;
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ class DirectByteBuffer extends ByteBuffer {
|
|||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPut(position, length);
|
checkPut(position, length, false);
|
||||||
|
|
||||||
unsafe.copyMemory
|
unsafe.copyMemory
|
||||||
(src, baseOffset + offset, null, address + position, length);
|
(src, baseOffset + offset, null, address + position, length);
|
||||||
@ -84,7 +84,7 @@ class DirectByteBuffer extends ByteBuffer {
|
|||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
checkGet(position, length);
|
checkGet(position, length, false);
|
||||||
|
|
||||||
unsafe.copyMemory
|
unsafe.copyMemory
|
||||||
(null, address + position, dst, baseOffset + offset, length);
|
(null, address + position, dst, baseOffset + offset, length);
|
||||||
|
@ -26,7 +26,7 @@ public class DatagramChannel extends SelectableChannel
|
|||||||
{
|
{
|
||||||
public static final int InvalidSocket = -1;
|
public static final int InvalidSocket = -1;
|
||||||
|
|
||||||
private int socket = InvalidSocket;
|
private int socket = makeSocket();
|
||||||
private boolean blocking = true;
|
private boolean blocking = true;
|
||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
|
|
||||||
@ -80,8 +80,12 @@ public class DatagramChannel extends SelectableChannel
|
|||||||
throw new UnsupportedAddressTypeException();
|
throw new UnsupportedAddressTypeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
socket = bind(inetAddress.getHostName(), inetAddress.getPort());
|
if (inetAddress == null) {
|
||||||
configureBlocking();
|
bind(socket, 0, 0);
|
||||||
|
} else {
|
||||||
|
bind(socket, inetAddress.getAddress().getRawAddress(),
|
||||||
|
inetAddress.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -94,10 +98,8 @@ public class DatagramChannel extends SelectableChannel
|
|||||||
throw new UnsupportedAddressTypeException();
|
throw new UnsupportedAddressTypeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
socket = connect(inetAddress.getHostName(), inetAddress.getPort());
|
connected = connect(socket, inetAddress.getAddress().getRawAddress(),
|
||||||
configureBlocking();
|
inetAddress.getPort());
|
||||||
|
|
||||||
if (socket != 0) connected = true;
|
|
||||||
|
|
||||||
return this;
|
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) {
|
private static String ipv4ToString(int address) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
@ -178,22 +205,35 @@ public class DatagramChannel extends SelectableChannel
|
|||||||
|
|
||||||
/** TODO: This is probably incomplete. */
|
/** TODO: This is probably incomplete. */
|
||||||
public DatagramChannel disconnect() throws IOException {
|
public DatagramChannel disconnect() throws IOException {
|
||||||
close();
|
connect(socket, 0, 0);
|
||||||
connected = false;
|
connected = false;
|
||||||
return this;
|
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)
|
private static native void configureBlocking(int socket, boolean blocking)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
private static native int bind(String hostname, int port)
|
private static native void bind(int socket, int host, int port)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
private static native int connect(String hostname, int port)
|
private static native boolean connect(int socket, int host, int port)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
private static native int write(int socket, byte[] array, int offset,
|
private static native int write(int socket, byte[] array, int offset,
|
||||||
int length, boolean blocking)
|
int length, boolean blocking)
|
||||||
throws IOException;
|
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,
|
private static native int receive(int socket, byte[] array, int offset,
|
||||||
int length, boolean blocking,
|
int length, boolean blocking,
|
||||||
int[] address)
|
int[] address)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
private static native void close(int socket);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
Socket.init();
|
||||||
|
|
||||||
return natDoListen(host, port);
|
natDoListen(socket, host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Handle extends ServerSocket {
|
public class Handle extends ServerSocket {
|
||||||
@ -82,11 +82,10 @@ public class ServerSocketChannel extends SelectableChannel {
|
|||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
channel.socket = doListen(a.getHostName(), a.getPort());
|
doListen(channel.socket, a.getAddress().getRawAddress(), a.getPort());
|
||||||
channel.configureBlocking(channel.isBlocking());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native int natDoAccept(int socket) throws IOException;
|
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;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public class SocketChannel extends SelectableChannel
|
|||||||
{
|
{
|
||||||
public static final int InvalidSocket = -1;
|
public static final int InvalidSocket = -1;
|
||||||
|
|
||||||
int socket = InvalidSocket;
|
int socket = makeSocket();
|
||||||
boolean connected = false;
|
boolean connected = false;
|
||||||
boolean readyToConnect = false;
|
boolean readyToConnect = false;
|
||||||
boolean blocking = true;
|
boolean blocking = true;
|
||||||
@ -64,7 +64,7 @@ public class SocketChannel extends SelectableChannel
|
|||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
throw new UnsupportedAddressTypeException();
|
throw new UnsupportedAddressTypeException();
|
||||||
}
|
}
|
||||||
socket = doConnect(a.getHostName(), a.getPort());
|
doConnect(socket, a.getAddress().getRawAddress(), a.getPort());
|
||||||
configureBlocking(blocking);
|
configureBlocking(blocking);
|
||||||
return connected;
|
return connected;
|
||||||
}
|
}
|
||||||
@ -98,13 +98,10 @@ public class SocketChannel extends SelectableChannel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int doConnect(String host, int port) throws IOException {
|
private void doConnect(int socket, int host, int port)
|
||||||
if (host == null) throw new NullPointerException();
|
throws IOException
|
||||||
|
{
|
||||||
boolean b[] = new boolean[1];
|
connected = natDoConnect(socket, host, port);
|
||||||
int s = natDoConnect(host, port, blocking, b);
|
|
||||||
connected = b[0];
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int read(ByteBuffer b) throws IOException {
|
public int read(ByteBuffer b) throws IOException {
|
||||||
@ -170,21 +167,40 @@ public class SocketChannel extends SelectableChannel
|
|||||||
|
|
||||||
public class Handle extends Socket {
|
public class Handle extends Socket {
|
||||||
public Handle() throws IOException {
|
public Handle() throws IOException {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTcpNoDelay(boolean on) throws SocketException {
|
public void setTcpNoDelay(boolean on) throws SocketException {
|
||||||
natSetTcpNoDelay(socket, on);
|
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)
|
private static native void configureBlocking(int socket, boolean blocking)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
private static native void natSetTcpNoDelay(int socket, boolean on)
|
private static native void natSetTcpNoDelay(int socket, boolean on)
|
||||||
throws SocketException;
|
throws SocketException;
|
||||||
|
private static native void bind(int socket, int host, int port)
|
||||||
private static native int natDoConnect(String host, int port, boolean blocking, boolean[] connected)
|
throws IOException;
|
||||||
|
private static native boolean natDoConnect(int socket, int host, int port)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
private static native void natFinishConnect(int socket)
|
private static native void natFinishConnect(int socket)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.BufferUnderflowException;
|
||||||
|
import java.nio.BufferOverflowException;
|
||||||
|
|
||||||
public class Buffers {
|
public class Buffers {
|
||||||
static {
|
static {
|
||||||
@ -57,7 +59,7 @@ public class Buffers {
|
|||||||
|
|
||||||
private static native void freeNative(ByteBuffer b);
|
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() {
|
Factory array = new Factory() {
|
||||||
public ByteBuffer allocate(int capacity) {
|
public ByteBuffer allocate(int capacity) {
|
||||||
return ByteBuffer.allocate(capacity);
|
return ByteBuffer.allocate(capacity);
|
||||||
@ -99,6 +101,34 @@ public class Buffers {
|
|||||||
test(native_, array);
|
test(native_, array);
|
||||||
test(native_, direct);
|
test(native_, direct);
|
||||||
test(native_, native_);
|
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 {
|
private interface Factory {
|
||||||
|
@ -22,20 +22,28 @@ public class Datagrams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
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 String Hostname = "localhost";
|
||||||
final int Port = 22043;
|
final int InPort = 22043;
|
||||||
final SocketAddress Address = new InetSocketAddress(Hostname, Port);
|
final int OutPort = 22044;
|
||||||
|
final SocketAddress InAddress = new InetSocketAddress(Hostname, InPort);
|
||||||
|
final SocketAddress OutAddress = new InetSocketAddress(Hostname, OutPort);
|
||||||
final byte[] Message = "hello, world!".getBytes();
|
final byte[] Message = "hello, world!".getBytes();
|
||||||
|
|
||||||
DatagramChannel out = DatagramChannel.open();
|
DatagramChannel out = DatagramChannel.open();
|
||||||
try {
|
try {
|
||||||
out.configureBlocking(false);
|
out.configureBlocking(false);
|
||||||
out.connect(Address);
|
out.socket().bind(OutAddress);
|
||||||
|
if (! send) out.connect(InAddress);
|
||||||
|
|
||||||
DatagramChannel in = DatagramChannel.open();
|
DatagramChannel in = DatagramChannel.open();
|
||||||
try {
|
try {
|
||||||
in.configureBlocking(false);
|
in.configureBlocking(false);
|
||||||
in.socket().bind(Address);
|
in.socket().bind(InAddress);
|
||||||
|
|
||||||
Selector selector = Selector.open();
|
Selector selector = Selector.open();
|
||||||
try {
|
try {
|
||||||
@ -53,14 +61,18 @@ public class Datagrams {
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case 0: {
|
case 0: {
|
||||||
if (outKey.isWritable()) {
|
if (outKey.isWritable()) {
|
||||||
out.write(ByteBuffer.wrap(Message));
|
if (send) {
|
||||||
|
out.send(ByteBuffer.wrap(Message), InAddress);
|
||||||
|
} else {
|
||||||
|
out.write(ByteBuffer.wrap(Message));
|
||||||
|
}
|
||||||
state = 1;
|
state = 1;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 1: {
|
case 1: {
|
||||||
if (inKey.isReadable()) {
|
if (inKey.isReadable()) {
|
||||||
in.receive(inBuffer);
|
expect(in.receive(inBuffer).equals(OutAddress));
|
||||||
if (! inBuffer.hasRemaining()) {
|
if (! inBuffer.hasRemaining()) {
|
||||||
expect(equal(inBuffer.array(),
|
expect(equal(inBuffer.array(),
|
||||||
inBuffer.arrayOffset(),
|
inBuffer.arrayOffset(),
|
||||||
|
@ -206,5 +206,12 @@ public class Strings {
|
|||||||
expect("abc".lastIndexOf('b', 100) == 1);
|
expect("abc".lastIndexOf('b', 100) == 1);
|
||||||
|
|
||||||
testTrivialPattern();
|
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())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user