implement DatagramChannel.receive and fix Datagrams to be Java 6 compatible

This commit is contained in:
Joel Dice 2012-07-10 14:09:14 -06:00
parent d8483d720d
commit 9974d91648
4 changed files with 150 additions and 20 deletions

View File

@ -337,6 +337,26 @@ doRead(int fd, void* buffer, size_t count)
#endif
}
int
doRecv(int fd, void* buffer, size_t count, int32_t* host, int32_t* port)
{
sockaddr address;
socklen_t length = sizeof(address);
int r = recvfrom
(fd, static_cast<char*>(buffer), count, 0, &address, &length);
if (r > 0) {
sockaddr_in a; memcpy(&a, &address, length);
*host = ntohl(a.sin_addr.s_addr);
*port = ntohs(a.sin_port);
} else {
*host = 0;
*port = 0;
}
return r;
}
int
doWrite(int fd, const void* buffer, size_t count)
{
@ -529,16 +549,54 @@ Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e,
}
extern "C" JNIEXPORT jint JNICALL
Java_java_nio_channels_DatagramChannel_read(JNIEnv* e,
jclass c,
jint socket,
jbyteArray buffer,
jint offset,
jint length,
jboolean blocking)
Java_java_nio_channels_DatagramChannel_receive(JNIEnv* e,
jclass,
jint socket,
jbyteArray buffer,
jint offset,
jint length,
jboolean blocking,
jintArray address)
{
return Java_java_nio_channels_SocketChannel_natRead
(e, c, socket, buffer, offset, length, blocking);
int r;
int32_t host;
int32_t port;
if (blocking) {
uint8_t* buf = static_cast<uint8_t*>(allocate(e, length));
if (buf) {
r = ::doRecv(socket, buf, length, &host, &port);
if (r > 0) {
e->SetByteArrayRegion
(buffer, offset, r, reinterpret_cast<jbyte*>(buf));
}
free(buf);
} else {
return 0;
}
} else {
jboolean isCopy;
uint8_t* buf = static_cast<uint8_t*>
(e->GetPrimitiveArrayCritical(buffer, &isCopy));
r = ::doRecv(socket, buf + offset, length, &host, &port);
e->ReleasePrimitiveArrayCritical(buffer, buf, 0);
}
if (r < 0) {
if (eagain()) {
return 0;
} else {
throwIOException(e);
}
} else if (r == 0) {
return -1;
} else {
e->SetIntArrayRegion(address, 0, 1, &host);
e->SetIntArrayRegion(address, 1, 1, &port);
}
return r;
}
extern "C" JNIEXPORT jint JNICALL

View File

@ -0,0 +1,19 @@
/* Copyright (c) 2012, 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;
import java.io.IOException;
public abstract class DatagramSocket {
public abstract SocketAddress getRemoteSocketAddress();
public abstract void bind(SocketAddress address) throws SocketException;
}

View File

@ -16,6 +16,8 @@ import java.net.SocketAddress;
import java.net.InetSocketAddress;
import java.net.ProtocolFamily;
import java.net.Socket;
import java.net.SocketException;
import java.net.DatagramSocket;
import java.net.StandardProtocolFamily;
public class DatagramChannel extends SelectableChannel
@ -26,7 +28,7 @@ public class DatagramChannel extends SelectableChannel
private int socket = InvalidSocket;
private boolean blocking = true;
public DatagramChannel configureBlocking(boolean v) throws IOException {
public SelectableChannel configureBlocking(boolean v) throws IOException {
blocking = v;
if (socket != InvalidSocket) {
configureBlocking(socket, v);
@ -54,6 +56,16 @@ public class DatagramChannel extends SelectableChannel
}
}
public static DatagramChannel open()
throws IOException
{
return open(StandardProtocolFamily.INET);
}
public DatagramSocket socket() {
return new Handle();
}
public DatagramChannel bind(SocketAddress address) throws IOException {
InetSocketAddress inetAddress;
try {
@ -97,19 +109,59 @@ public class DatagramChannel extends SelectableChannel
}
public int read(ByteBuffer b) throws IOException {
if (b.remaining() == 0) return 0;
int p = b.position();
receive(b);
return b.position() - p;
}
public SocketAddress receive(ByteBuffer b) throws IOException {
if (b.remaining() == 0) return null;
byte[] array = b.array();
if (array == null) throw new NullPointerException();
int c = read
(socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking);
int[] address = new int[2];
int c = receive
(socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking,
address);
if (c > 0) {
b.position(b.position() + c);
return new InetSocketAddress(ipv4ToString(address[0]), address[1]);
} else {
return null;
}
}
private static String ipv4ToString(int address) {
StringBuilder sb = new StringBuilder();
sb.append( address >> 24 ).append('.')
.append((address >> 16) & 0xFF).append('.')
.append((address >> 8) & 0xFF).append('.')
.append( address & 0xFF);
return sb.toString();
}
public class Handle extends DatagramSocket {
public SocketAddress getRemoteSocketAddress() {
throw new UnsupportedOperationException();
}
return c;
public void bind(SocketAddress address) throws SocketException {
try {
DatagramChannel.this.bind(address);
} catch (SocketException e) {
throw e;
} catch (IOException e) {
SocketException se = new SocketException();
se.initCause(e);
throw se;
}
}
}
private static native void configureBlocking(int socket, boolean blocking)
@ -121,7 +173,8 @@ public class DatagramChannel extends SelectableChannel
private static native int write(int socket, byte[] array, int offset,
int length, boolean blocking)
throws IOException;
private static native int read(int socket, byte[] array, int offset,
int length, boolean blocking)
private static native int receive(int socket, byte[] array, int offset,
int length, boolean blocking,
int[] address)
throws IOException;
}

View File

@ -27,15 +27,15 @@ public class Datagrams {
final SocketAddress Address = new InetSocketAddress(Hostname, Port);
final byte[] Message = "hello, world!".getBytes();
DatagramChannel out = DatagramChannel.open(StandardProtocolFamily.INET);
DatagramChannel out = DatagramChannel.open();
try {
out.configureBlocking(false);
out.connect(Address);
DatagramChannel in = DatagramChannel.open(StandardProtocolFamily.INET);
DatagramChannel in = DatagramChannel.open();
try {
in.configureBlocking(false);
in.bind(Address);
in.socket().bind(Address);
Selector selector = Selector.open();
try {
@ -60,7 +60,7 @@ public class Datagrams {
case 1: {
if (inKey.isReadable()) {
in.read(inBuffer);
in.receive(inBuffer);
if (! inBuffer.hasRemaining()) {
expect(equal(inBuffer.array(),
inBuffer.arrayOffset(),