mirror of
https://github.com/corda/corda.git
synced 2025-01-19 03:06:36 +00:00
Merge branch 'master' of dice:git/vm
This commit is contained in:
commit
abc46c3d30
576
classpath/java-nio.cpp
Normal file
576
classpath/java-nio.cpp
Normal file
@ -0,0 +1,576 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef WIN32
|
||||
# include <winsock2.h>
|
||||
#else
|
||||
# include <fcntl.h>
|
||||
# include <errno.h>
|
||||
# include <netdb.h>
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni-util.h"
|
||||
|
||||
#undef JNIEXPORT
|
||||
#define JNIEXPORT __attribute__ ((visibility("default")))
|
||||
|
||||
#define java_nio_channels_SelectionKey_OP_READ 1L
|
||||
#define java_nio_channels_SelectionKey_OP_WRITE 4L
|
||||
#define java_nio_channels_SelectionKey_OP_ACCEPT 16L
|
||||
|
||||
namespace {
|
||||
|
||||
inline const char*
|
||||
errorString(int e)
|
||||
{
|
||||
return strerror(e);
|
||||
}
|
||||
|
||||
inline const char*
|
||||
errorString()
|
||||
{
|
||||
#ifdef WIN32
|
||||
const unsigned size = 64;
|
||||
char buffer[size];
|
||||
snprintf(buffer, size, "wsa code: %d", WSAGetLastError());
|
||||
return JvNewStringLatin1(buffer);
|
||||
#else
|
||||
return errorString(errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
throwIOException(JNIEnv* e)
|
||||
{
|
||||
throwNew(e, "java/io/IOException", errorString());
|
||||
}
|
||||
|
||||
void
|
||||
init(JNIEnv* e, sockaddr_in* address, jstring hostString, jint port)
|
||||
{
|
||||
const char* chars = e->GetStringUTFChars(hostString, 0);
|
||||
if (chars) {
|
||||
hostent* host = gethostbyname(chars);
|
||||
e->ReleaseStringUTFChars(hostString, chars);
|
||||
if (host == 0) {
|
||||
// herror("init: gethostbyname");
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
einProgress()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return WSAGetLastError() == WSAEINPROGRESS
|
||||
or WSAGetLastError() == WSAEWOULDBLOCK;
|
||||
#else
|
||||
return errno == EINPROGRESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool
|
||||
eagain()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return WSAGetLastError() == WSAEINPROGRESS
|
||||
or WSAGetLastError() == WSAEWOULDBLOCK;
|
||||
#else
|
||||
return errno == EAGAIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
makeNonblocking(JNIEnv* e, int d)
|
||||
{
|
||||
#ifdef WIN32
|
||||
u_long a = 1;
|
||||
int r = ioctlsocket(d, FIONBIO, &a);
|
||||
if (r != 0) throw new IOException(errorString());
|
||||
#else
|
||||
int r = fcntl(d, F_SETFL, fcntl(d, F_GETFL) | O_NONBLOCK);
|
||||
if (r < 0) {
|
||||
throwIOException(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
doListen(JNIEnv* e, int s, sockaddr_in* address)
|
||||
{
|
||||
int opt = 1;
|
||||
int r = ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
reinterpret_cast<char*>(&opt), sizeof(int));
|
||||
if (r != 0) {
|
||||
throwIOException(e);
|
||||
return;
|
||||
}
|
||||
|
||||
r = ::bind(s, reinterpret_cast<sockaddr*>(address), sizeof(sockaddr_in));
|
||||
if (r != 0) {
|
||||
throwIOException(e);
|
||||
return;
|
||||
}
|
||||
|
||||
r = ::listen(s, 100);
|
||||
if (r != 0) {
|
||||
throwIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
doConnect(JNIEnv* e, int s, sockaddr_in* address)
|
||||
{
|
||||
int r = ::connect(s, reinterpret_cast<sockaddr*>(address),
|
||||
sizeof(sockaddr_in));
|
||||
if (r == 0) {
|
||||
return true;
|
||||
} else if (not einProgress()) {
|
||||
throwIOException(e);
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
doAccept(JNIEnv* e, int s)
|
||||
{
|
||||
sockaddr address;
|
||||
socklen_t length = sizeof(address);
|
||||
int r = ::accept(s, &address, &length);
|
||||
if (r >= 0) {
|
||||
// System::out->print(JvNewStringLatin1("doAccept: socket: "));
|
||||
// System::out->println(String::valueOf((jint) r));
|
||||
|
||||
makeNonblocking(e, r);
|
||||
return r;
|
||||
} else {
|
||||
throwIOException(e);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
doRead(int fd, void* buffer, size_t count)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return recv(fd, static_cast<char*>(buffer), count, 0);
|
||||
#else
|
||||
return read(fd, buffer, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
doWrite(int fd, const void* buffer, size_t count)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return send(fd, static_cast<const char*>(buffer), count, 0);
|
||||
#else
|
||||
return write(fd, buffer, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
makeSocket(JNIEnv* e, bool blocking = false)
|
||||
{
|
||||
#ifdef WIN32
|
||||
static bool wsaInitialized = false;
|
||||
if (not wsaInitialized) {
|
||||
WSADATA data;
|
||||
int r = WSAStartup(MAKEWORD(2, 2), &data);
|
||||
if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) {
|
||||
throw new IOException(JvNewStringLatin1("WSAStartup failed"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (s < 0) { throwIOException(e); return s; }
|
||||
|
||||
// System::out->print(JvNewStringLatin1("makeSocket: socket: "));
|
||||
// System::out->println(String::valueOf((jint) s));
|
||||
|
||||
if (not blocking) makeNonblocking(e, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace <anonymous>
|
||||
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_java_nio_channels_ServerSocketChannel_natDoAccept(JNIEnv *e, jclass, jint socket)
|
||||
{
|
||||
return ::doAccept(e, socket);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv *e,
|
||||
jclass,
|
||||
jstring host,
|
||||
jint port)
|
||||
{
|
||||
int s = makeSocket(e);
|
||||
if (s < 0) return s;
|
||||
|
||||
sockaddr_in address;
|
||||
init(e, &address, host, port);
|
||||
|
||||
::doListen(e, s, &address);
|
||||
return s;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e,
|
||||
jclass,
|
||||
jstring host,
|
||||
jint port,
|
||||
jbooleanArray retVal)
|
||||
{
|
||||
int s = makeSocket(e);
|
||||
|
||||
sockaddr_in address;
|
||||
init(e, &address, host, port);
|
||||
|
||||
jboolean connected = ::doConnect(e, s, &address);
|
||||
e->SetBooleanArrayRegion(retVal, 0, 1, &connected);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e,
|
||||
jclass,
|
||||
jint socket,
|
||||
jbyteArray buffer,
|
||||
jint offset,
|
||||
jint length)
|
||||
{
|
||||
jboolean isCopy;
|
||||
uint8_t *buf =
|
||||
reinterpret_cast<uint8_t*>(e->GetPrimitiveArrayCritical(buffer, &isCopy));
|
||||
int r = ::doRead(socket, buf + offset, length);
|
||||
e->ReleasePrimitiveArrayCritical(buffer, buf, 0);
|
||||
if (r < 0) {
|
||||
if (eagain()) {
|
||||
return 0;
|
||||
} else {
|
||||
throwIOException(e);
|
||||
}
|
||||
} else if (r == 0) {
|
||||
return -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e,
|
||||
jclass,
|
||||
jint socket,
|
||||
jbyteArray buffer,
|
||||
jint offset,
|
||||
jint length)
|
||||
{
|
||||
jboolean isCopy;
|
||||
uint8_t *buf =
|
||||
reinterpret_cast<uint8_t*>(e->GetPrimitiveArrayCritical(buffer, &isCopy));
|
||||
int r = ::doWrite(socket, 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,
|
||||
jint socket)
|
||||
{
|
||||
int error;
|
||||
socklen_t size = sizeof(int);
|
||||
int r = getsockopt(socket, SOL_SOCKET, SO_ERROR,
|
||||
reinterpret_cast<char*>(&error), &size);
|
||||
if (r != 0 or size != sizeof(int) or error != 0) {
|
||||
throwNew(e, "java/io/IOException", errorString(error));
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_nio_channels_SocketChannel_natCloseSocket(JNIEnv *,
|
||||
jclass,
|
||||
jint socket)
|
||||
{
|
||||
close(socket);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class Pipe {
|
||||
public:
|
||||
#ifdef WIN32
|
||||
// The Windows socket API only accepts socket file descriptors, not
|
||||
// pipe descriptors or others. Thus, to implement
|
||||
// Selector.wakeup(), we make a socket connection via the loopback
|
||||
// interface and use it as a pipe.
|
||||
Pipe(): connected_(false), listener_(-1), reader_(-1), writer_(-1) {
|
||||
sockaddr_in address;
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = 0;
|
||||
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //INADDR_LOOPBACK;
|
||||
listener_ = makeSocket();
|
||||
::doListen(listener_, &address);
|
||||
|
||||
socklen_t length = sizeof(sockaddr_in);
|
||||
int r = getsockname(listener_, reinterpret_cast<sockaddr*>(&address),
|
||||
&length);
|
||||
if (r) {
|
||||
throw new IOException(errorString());
|
||||
}
|
||||
|
||||
writer_ = makeSocket(true);
|
||||
connected_ = ::doConnect(writer_, &address);
|
||||
}
|
||||
|
||||
~Pipe() {
|
||||
if (listener_ >= 0) ::close(listener_);
|
||||
if (reader_ >= 0) ::close(reader_);
|
||||
if (writer_ >= 0) ::close(writer_);
|
||||
}
|
||||
|
||||
bool connected() {
|
||||
return connected_;
|
||||
}
|
||||
|
||||
void setConnected(bool v) {
|
||||
connected_ = v;
|
||||
}
|
||||
|
||||
int listener() {
|
||||
return listener_;
|
||||
}
|
||||
|
||||
void setListener(int v) {
|
||||
listener_ = v;
|
||||
}
|
||||
|
||||
int reader() {
|
||||
return reader_;
|
||||
}
|
||||
|
||||
void setReader(int v) {
|
||||
reader_ = v;
|
||||
}
|
||||
|
||||
int writer() {
|
||||
return writer_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool connected_;
|
||||
int listener_;
|
||||
int reader_;
|
||||
int writer_;
|
||||
#else
|
||||
Pipe(JNIEnv* e) {
|
||||
if (::pipe(pipe) != 0) {
|
||||
throwIOException(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (makeNonblocking(e, pipe[0])) {
|
||||
makeNonblocking(e, pipe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
::close(pipe[0]);
|
||||
::close(pipe[1]);
|
||||
}
|
||||
|
||||
bool connected() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int reader() {
|
||||
return pipe[0];
|
||||
}
|
||||
|
||||
int writer() {
|
||||
return pipe[1];
|
||||
}
|
||||
|
||||
private:
|
||||
int pipe[2];
|
||||
#endif
|
||||
};
|
||||
|
||||
struct SelectorState {
|
||||
fd_set read;
|
||||
fd_set write;
|
||||
fd_set except;
|
||||
Pipe control;
|
||||
SelectorState(JNIEnv* e) : control(e) { }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
inline void* operator new(size_t, void* p) throw() { return p; }
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_java_nio_channels_SocketSelector_natInit(JNIEnv* e, jclass)
|
||||
{
|
||||
void *mem = malloc(sizeof(SelectorState));
|
||||
if (mem) {
|
||||
SelectorState *s = new (mem) SelectorState(e);
|
||||
|
||||
if (s) {
|
||||
FD_ZERO(&(s->read));
|
||||
FD_ZERO(&(s->write));
|
||||
FD_ZERO(&(s->except));
|
||||
return reinterpret_cast<jlong>(s);
|
||||
}
|
||||
}
|
||||
throwNew(e, "java/lang/OutOfMemoryError", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_nio_channels_SocketSelector_natWakeup(JNIEnv *e, jclass, jlong state)
|
||||
{
|
||||
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
||||
if (s->control.connected()) {
|
||||
const char c = 1;
|
||||
int r = ::doWrite(s->control.writer(), &c, 1);
|
||||
if (r != 1) {
|
||||
throwIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_nio_channels_SocketSelector_natClearWoken(JNIEnv *e, jclass, jlong state)
|
||||
{
|
||||
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
||||
if (s->control.connected() and s->control.reader() >= 0) {
|
||||
char c;
|
||||
int r = ::doRead(s->control.reader(), &c, 1);
|
||||
if (r != 1) {
|
||||
throwIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_nio_channels_SocketSelector_natClose(JNIEnv *, jclass, jlong state)
|
||||
{
|
||||
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
||||
s->control.dispose();
|
||||
free(s);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_java_nio_channels_SocketSelector_natSelectClearAll(JNIEnv *, jclass,
|
||||
jint socket,
|
||||
jlong state)
|
||||
{
|
||||
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
||||
FD_CLR(socket, &(s->read));
|
||||
FD_CLR(socket, &(s->write));
|
||||
FD_CLR(socket, &(s->except));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_java_nio_channels_SocketSelector_natSelectUpdateInterestSet(JNIEnv *,
|
||||
jclass,
|
||||
jint socket,
|
||||
jint interest,
|
||||
jlong state,
|
||||
jint max)
|
||||
{
|
||||
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
||||
if (interest & (java_nio_channels_SelectionKey_OP_READ |
|
||||
java_nio_channels_SelectionKey_OP_ACCEPT)) {
|
||||
FD_SET(socket, &(s->read));
|
||||
if (max < socket) max = socket;
|
||||
} else {
|
||||
FD_CLR(socket, &(s->read));
|
||||
}
|
||||
|
||||
if (interest & java_nio_channels_SelectionKey_OP_WRITE) {
|
||||
FD_SET(socket, &(s->write));
|
||||
if (max < socket) max = socket;
|
||||
} else {
|
||||
FD_CLR(socket, &(s->write));
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_java_nio_channels_SocketSelector_natDoSocketSelect(JNIEnv *e, jclass,
|
||||
jlong state,
|
||||
jint max,
|
||||
jlong interval)
|
||||
{
|
||||
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
||||
if (s->control.reader() >= 0) {
|
||||
int socket = s->control.reader();
|
||||
FD_SET(socket, &(s->read));
|
||||
if (max < socket) max = socket;
|
||||
}
|
||||
timeval time = { interval / 1000, (interval % 1000) * 1000 };
|
||||
int r = ::select(max + 1, &(s->read), &(s->write), &(s->except), &time);
|
||||
if (r < 0) {
|
||||
if (errno != EINTR) {
|
||||
throwIOException(e);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_java_nio_channels_SocketSelector_natUpdateReadySet(JNIEnv *, jclass,
|
||||
jint socket,
|
||||
jint interest,
|
||||
jlong state)
|
||||
{
|
||||
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
||||
jint ready = 0;
|
||||
|
||||
if (FD_ISSET(socket, &(s->read))) {
|
||||
if (interest & java_nio_channels_SelectionKey_OP_READ) {
|
||||
ready |= java_nio_channels_SelectionKey_OP_READ;
|
||||
}
|
||||
|
||||
if (interest & java_nio_channels_SelectionKey_OP_ACCEPT) {
|
||||
ready |= java_nio_channels_SelectionKey_OP_ACCEPT;
|
||||
}
|
||||
}
|
||||
|
||||
if ((interest & java_nio_channels_SelectionKey_OP_WRITE)
|
||||
and FD_ISSET(socket, &(s->write))) {
|
||||
ready |= java_nio_channels_SelectionKey_OP_WRITE;
|
||||
}
|
||||
return ready;
|
||||
}
|
||||
|
||||
|
19
classpath/java/net/InetSocketAddress.java
Normal file
19
classpath/java/net/InetSocketAddress.java
Normal file
@ -0,0 +1,19 @@
|
||||
package java.net;
|
||||
|
||||
public class InetSocketAddress {
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
public InetSocketAddress(String host, int port) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
}
|
@ -60,7 +60,9 @@ public class ByteBuffer {
|
||||
if (position != 0) {
|
||||
System.arraycopy(array, arrayOffset+position, array, arrayOffset, remaining());
|
||||
}
|
||||
position=0;
|
||||
position=remaining();
|
||||
limit(capacity());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
8
classpath/java/nio/channels/Channel.java
Normal file
8
classpath/java/nio/channels/Channel.java
Normal file
@ -0,0 +1,8 @@
|
||||
package java.nio.channels;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Channel {
|
||||
public void close() throws IOException;
|
||||
public boolean isOpen();
|
||||
}
|
8
classpath/java/nio/channels/ReadableByteChannel.java
Normal file
8
classpath/java/nio/channels/ReadableByteChannel.java
Normal file
@ -0,0 +1,8 @@
|
||||
package java.nio.channels;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface ReadableByteChannel extends Channel {
|
||||
public int read(ByteBuffer b) throws IOException;
|
||||
}
|
28
classpath/java/nio/channels/SelectableChannel.java
Normal file
28
classpath/java/nio/channels/SelectableChannel.java
Normal file
@ -0,0 +1,28 @@
|
||||
package java.nio.channels;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public abstract class SelectableChannel implements Channel {
|
||||
private SelectionKey key;
|
||||
|
||||
public abstract int read(ByteBuffer b) throws Exception;
|
||||
public abstract int write(ByteBuffer b) throws Exception;
|
||||
public abstract boolean isOpen();
|
||||
|
||||
public SelectionKey register(Selector selector, int interestOps,
|
||||
Object attachment)
|
||||
{
|
||||
SelectionKey key = new SelectionKey
|
||||
(this, selector, interestOps, attachment);
|
||||
selector.add(key);
|
||||
return key;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (key != null) {
|
||||
key.selector().remove(key);
|
||||
key = null;
|
||||
}
|
||||
}
|
||||
}
|
68
classpath/java/nio/channels/SelectionKey.java
Normal file
68
classpath/java/nio/channels/SelectionKey.java
Normal file
@ -0,0 +1,68 @@
|
||||
package java.nio.channels;
|
||||
|
||||
public class SelectionKey {
|
||||
public static final int OP_READ = 1 << 0;
|
||||
public static final int OP_WRITE = 1 << 2;
|
||||
public static final int OP_ACCEPT = 1 << 4;
|
||||
// public static final int OP_CONNECT = 1 << 3;
|
||||
|
||||
private final SelectableChannel channel;
|
||||
private final Selector selector;
|
||||
private int interestOps;
|
||||
private int readyOps;
|
||||
private final Object attachment;
|
||||
|
||||
public SelectionKey(SelectableChannel channel, Selector selector,
|
||||
int interestOps, Object attachment)
|
||||
{
|
||||
this.channel = channel;
|
||||
this.selector = selector;
|
||||
this.interestOps = interestOps;
|
||||
this.attachment = attachment;
|
||||
this.readyOps = 0;
|
||||
}
|
||||
|
||||
public int interestOps() {
|
||||
return interestOps;
|
||||
}
|
||||
|
||||
public void interestOps(int v) {
|
||||
this.interestOps = v;
|
||||
}
|
||||
|
||||
public int readyOps() {
|
||||
return readyOps;
|
||||
}
|
||||
|
||||
public void readyOps(int v) {
|
||||
this.readyOps = v;
|
||||
}
|
||||
|
||||
public boolean isReadable() {
|
||||
return (readyOps & OP_READ) != 0;
|
||||
}
|
||||
|
||||
public boolean isWritable() {
|
||||
return (readyOps & OP_WRITE) != 0;
|
||||
}
|
||||
|
||||
public boolean isAcceptable() {
|
||||
return (readyOps & OP_ACCEPT) != 0;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return channel.isOpen() && selector.isOpen();
|
||||
}
|
||||
|
||||
public SelectableChannel channel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public Selector selector() {
|
||||
return selector;
|
||||
}
|
||||
|
||||
public Object attachment() {
|
||||
return attachment;
|
||||
}
|
||||
}
|
38
classpath/java/nio/channels/Selector.java
Normal file
38
classpath/java/nio/channels/Selector.java
Normal file
@ -0,0 +1,38 @@
|
||||
package java.nio.channels;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
public abstract class Selector {
|
||||
protected final Set<SelectionKey> keys = new HashSet();
|
||||
protected final Set<SelectionKey> selectedKeys = new HashSet();
|
||||
|
||||
public static Selector open() {
|
||||
return new SocketSelector();
|
||||
}
|
||||
|
||||
public void add(SelectionKey key) {
|
||||
keys.add(key);
|
||||
}
|
||||
|
||||
public void remove(SelectionKey key) {
|
||||
keys.remove(key);
|
||||
}
|
||||
|
||||
public Set<SelectionKey> keys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
public Set<SelectionKey> selectedKeys() {
|
||||
return selectedKeys;
|
||||
}
|
||||
|
||||
public abstract boolean isOpen();
|
||||
|
||||
public abstract void wakeup();
|
||||
|
||||
public abstract void select(long interval) throws IOException;
|
||||
|
||||
public abstract void close();
|
||||
}
|
39
classpath/java/nio/channels/ServerSocketChannel.java
Normal file
39
classpath/java/nio/channels/ServerSocketChannel.java
Normal file
@ -0,0 +1,39 @@
|
||||
package java.nio.channels;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class ServerSocketChannel extends SocketChannel {
|
||||
public static ServerSocketChannel open() {
|
||||
return new ServerSocketChannel();
|
||||
}
|
||||
|
||||
public SocketChannel accept() throws Exception {
|
||||
SocketChannel c = new SocketChannel();
|
||||
c.socket = doAccept();
|
||||
c.connected = true;
|
||||
return c;
|
||||
}
|
||||
|
||||
public Handle socket() {
|
||||
return new Handle();
|
||||
}
|
||||
|
||||
private int doAccept() throws Exception {
|
||||
return natDoAccept(socket);
|
||||
}
|
||||
|
||||
private int doListen(String host, int port) throws Exception {
|
||||
return natDoListen(host, port);
|
||||
}
|
||||
|
||||
public class Handle {
|
||||
public void bind(InetSocketAddress address)
|
||||
throws Exception
|
||||
{
|
||||
socket = doListen(address.getHostName(), address.getPort());
|
||||
}
|
||||
}
|
||||
|
||||
private static native int natDoAccept(int socket) throws Exception;
|
||||
private static native int natDoListen(String host, int port) throws Exception;
|
||||
}
|
83
classpath/java/nio/channels/SocketChannel.java
Normal file
83
classpath/java/nio/channels/SocketChannel.java
Normal file
@ -0,0 +1,83 @@
|
||||
package java.nio.channels;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class SocketChannel extends SelectableChannel
|
||||
implements ReadableByteChannel, WritableByteChannel
|
||||
{
|
||||
public static final int InvalidSocket = -1;
|
||||
|
||||
protected int socket = InvalidSocket;
|
||||
protected boolean open = true;
|
||||
protected boolean connected = false;
|
||||
|
||||
public static SocketChannel open() {
|
||||
return new SocketChannel();
|
||||
}
|
||||
|
||||
public void configureBlocking(boolean v) {
|
||||
if (v) throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
public void connect(InetSocketAddress address) throws Exception {
|
||||
socket = doConnect(address.getHostName(), address.getPort());
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
if (! open) return;
|
||||
closeSocket();
|
||||
open = false;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
private int doConnect(String host, int port) throws Exception {
|
||||
boolean b[] = new boolean[1];
|
||||
int s = natDoConnect(host, port, b);
|
||||
connected = b[0];
|
||||
return s;
|
||||
}
|
||||
|
||||
public int read(ByteBuffer b) throws IOException {
|
||||
if (! open) return -1;
|
||||
if (b.remaining() == 0) return 0;
|
||||
int r = natRead(socket, b.array(), b.arrayOffset() + b.position(), b.remaining());
|
||||
if (r > 0) {
|
||||
b.position(b.position() + r);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public int write(ByteBuffer b) throws IOException {
|
||||
if (! connected) {
|
||||
natThrowWriteError(socket);
|
||||
}
|
||||
int w = natWrite(socket, b.array(), b.arrayOffset() + b.position(), b.remaining());
|
||||
if (w > 0) {
|
||||
b.position(b.position() + w);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
private void closeSocket() {
|
||||
natCloseSocket(socket);
|
||||
}
|
||||
|
||||
int socketFD() {
|
||||
return socket;
|
||||
}
|
||||
|
||||
private static native int natDoConnect(String host, int port, boolean[] connected)
|
||||
throws Exception;
|
||||
private static native int natRead(int socket, byte[] buffer, int offset, int length)
|
||||
throws IOException;
|
||||
private static native int natWrite(int socket, byte[] buffer, int offset, int length)
|
||||
throws IOException;
|
||||
private static native void natThrowWriteError(int socket) throws IOException;
|
||||
private static native void natCloseSocket(int socket);
|
||||
}
|
159
classpath/java/nio/channels/SocketSelector.java
Normal file
159
classpath/java/nio/channels/SocketSelector.java
Normal file
@ -0,0 +1,159 @@
|
||||
package java.nio.channels;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
class SocketSelector extends Selector {
|
||||
private static final boolean isWin32;
|
||||
protected long state;
|
||||
protected final Object lock = new Object();
|
||||
protected boolean woken = false;
|
||||
|
||||
static {
|
||||
isWin32 = false;
|
||||
}
|
||||
|
||||
public SocketSelector() {
|
||||
state = natInit();
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return state != 0;
|
||||
}
|
||||
|
||||
public void wakeup() {
|
||||
synchronized (lock) {
|
||||
if (! woken) {
|
||||
woken = true;
|
||||
|
||||
natWakeup(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean clearWoken() {
|
||||
synchronized (lock) {
|
||||
if (woken) {
|
||||
woken = false;
|
||||
natClearWoken(state);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void select(long interval) throws IOException {
|
||||
if (isWin32) {
|
||||
win32Select(interval);
|
||||
} else {
|
||||
posixSelect(interval);
|
||||
}
|
||||
}
|
||||
|
||||
private void win32Select(long interval) { }
|
||||
|
||||
private void posixSelect(long interval) throws IOException {
|
||||
selectedKeys.clear();
|
||||
|
||||
if (clearWoken()) return;
|
||||
int max=0;
|
||||
for (Iterator<SelectionKey> it = keys.iterator();
|
||||
it.hasNext();) {
|
||||
SelectionKey key = it.next();
|
||||
SocketChannel c = (SocketChannel)key.channel();
|
||||
int socket = c.socketFD();
|
||||
if (! c.isOpen()) {
|
||||
natSelectClearAll(socket, state);
|
||||
// Equivalent to:
|
||||
//
|
||||
// FD_CLR(socket, &(s->read));
|
||||
// FD_CLR(socket, &(s->write));
|
||||
// FD_CLR(socket, &(s->except));
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
key.readyOps(0);
|
||||
max = natSelectUpdateInterestSet(socket, key.interestOps(), state, max);
|
||||
// Equivalent to:
|
||||
//
|
||||
// if (interest & (SelectionKey::OP_READ | SelectionKey::OP_ACCEPT)) {
|
||||
// FD_SET(socket, &(s->read));
|
||||
// if (max < socket) max = socket;
|
||||
// } else {
|
||||
// FD_CLR(socket, &(s->read));
|
||||
// }
|
||||
//
|
||||
// if (interest & SelectionKey::OP_WRITE) {
|
||||
// FD_SET(socket, &(s->write));
|
||||
// if (max < socket) max = socket;
|
||||
// } else {
|
||||
// FD_CLR(socket, &(s->write));
|
||||
// }
|
||||
}
|
||||
|
||||
int r = natDoSocketSelect(state, max, interval);
|
||||
// Equivalent to:
|
||||
//
|
||||
// if (s->control.reader() >= 0) {
|
||||
// unsigned socket = s->control.reader();
|
||||
// FD_SET(socket, &(s->read));
|
||||
// if (max < socket) max = socket;
|
||||
// }
|
||||
// timeval time = { interval / 1000, (interval % 1000) * 1000 };
|
||||
// int r = ::select(max + 1, &(s->read), &(s->write), &(s->except), &time);
|
||||
// if (r < 0) {
|
||||
// if (errno != EINTR) {
|
||||
// throw new IOException(errorString());
|
||||
// }
|
||||
// }
|
||||
if (r > 0) {
|
||||
for (SelectionKey key : keys) {
|
||||
SocketChannel c = (SocketChannel)key.channel();
|
||||
int socket = c.socketFD();
|
||||
int ready = natUpdateReadySet(socket, key.interestOps(), state);
|
||||
// Equivalent to:
|
||||
//
|
||||
// jint ready = 0;
|
||||
//
|
||||
// if (FD_ISSET(c->socket, &(s->read))) {
|
||||
// if (interest & SelectionKey::OP_READ) {
|
||||
// ready |= SelectionKey::OP_READ;
|
||||
// }
|
||||
//
|
||||
// if (interest & SelectionKey::OP_ACCEPT) {
|
||||
// ready |= SelectionKey::OP_ACCEPT;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ((interest & SelectionKey::OP_WRITE)
|
||||
// and FD_ISSET(c->socket, &(s->write))) {
|
||||
// ready |= SelectionKey::OP_WRITE;
|
||||
// }
|
||||
key.readyOps(ready);
|
||||
if (ready != 0) {
|
||||
selectedKeys.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
clearWoken();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
natClose(state);
|
||||
}
|
||||
|
||||
private static native long natInit();
|
||||
private static native void natWakeup(long state);
|
||||
private static native void natClearWoken(long state);
|
||||
private static native void natClose(long state);
|
||||
private static native void natSelectClearAll(int socket, long state);
|
||||
private static native int natSelectUpdateInterestSet(int socket,
|
||||
int interest,
|
||||
long state,
|
||||
int max);
|
||||
private static native int natDoSocketSelect(long state, int max, long interval)
|
||||
throws IOException;
|
||||
private static native int natUpdateReadySet(int socket, int interest, long state);
|
||||
}
|
8
classpath/java/nio/channels/WritableByteChannel.java
Normal file
8
classpath/java/nio/channels/WritableByteChannel.java
Normal file
@ -0,0 +1,8 @@
|
||||
package java.nio.channels;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface WritableByteChannel extends Channel {
|
||||
public int write(ByteBuffer b) throws IOException;
|
||||
}
|
4
makefile
4
makefile
@ -1,4 +1,4 @@
|
||||
MAKEFLAGS = -s
|
||||
#MAKEFLAGS = -s
|
||||
|
||||
arch = $(shell uname -m)
|
||||
ifeq ($(arch),i586)
|
||||
@ -45,7 +45,7 @@ javac = javac
|
||||
strip = :
|
||||
show-size = :
|
||||
|
||||
warnings = -Wall -Wextra -Werror -Wold-style-cast -Wunused-parameter \
|
||||
warnings = -Wall -Wextra -Werror -Wunused-parameter \
|
||||
-Winit-self -Wconversion
|
||||
|
||||
thread-lflags = -lpthread
|
||||
|
71
test/SendFile.java
Normal file
71
test/SendFile.java
Normal file
@ -0,0 +1,71 @@
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.io.OutputStream;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
public class SendFile {
|
||||
private static class SocketOutputStream extends OutputStream {
|
||||
private final SocketChannel channel;
|
||||
private final Selector selector;
|
||||
public SocketOutputStream(String host, int port) throws Exception {
|
||||
channel = SocketChannel.open();
|
||||
channel.connect(new InetSocketAddress(host, port));
|
||||
channel.configureBlocking(false);
|
||||
selector = Selector.open();
|
||||
channel.register(selector, SelectionKey.OP_WRITE, null);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
channel.close();
|
||||
}
|
||||
|
||||
public void write(int c) {
|
||||
throw new RuntimeException("Do not use!");
|
||||
}
|
||||
public void write(byte[] buffer, int offset, int length)
|
||||
throws IOException {
|
||||
ByteBuffer buf = ByteBuffer.wrap(buffer);
|
||||
buf.position(offset);
|
||||
buf.limit(offset+length);
|
||||
while (buf.hasRemaining()) {
|
||||
selector.select(10000);
|
||||
for (SelectionKey key : selector.selectedKeys()) {
|
||||
if (key.isWritable() && (key.channel() == channel)) {
|
||||
channel.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendFile(String file, String host, int port)
|
||||
throws Exception {
|
||||
System.out.println("Sending " + file);
|
||||
OutputStream os = new SocketOutputStream(host, port);
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
byte[] buf = new byte[16384];
|
||||
int count=-1;
|
||||
while ((count = is.read(buf)) >= 0) {
|
||||
os.write(buf, 0, count);
|
||||
}
|
||||
is.close();
|
||||
os.close();
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
if (args.length != 2) {
|
||||
System.out.println("Usage: SendFile file host");
|
||||
} else {
|
||||
try {
|
||||
sendFile(args[0], args[1], 8988);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
90
test/SendServer.java
Normal file
90
test/SendServer.java
Normal file
@ -0,0 +1,90 @@
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
public class SendServer {
|
||||
private static char cIndex = 'A';
|
||||
private static ByteBuffer inBuf = ByteBuffer.allocate(8192);
|
||||
|
||||
private static void dumpByteBuffer(char note, ByteBuffer buf) {
|
||||
System.out.println(note + ": Buffer position: " + buf.position() + " limit: " +
|
||||
buf.limit() + " capacity: " + buf.capacity() + " remaining: " +
|
||||
buf.remaining());
|
||||
}
|
||||
|
||||
private static class Connection {
|
||||
private final char myIndex;
|
||||
private final java.io.FileOutputStream fos;
|
||||
|
||||
public Connection() throws Exception {
|
||||
myIndex = cIndex++;
|
||||
fos = new java.io.FileOutputStream("dump." + myIndex);
|
||||
}
|
||||
|
||||
public void handleRead(SocketChannel channel) throws Exception {
|
||||
int count = -1;
|
||||
while ((count = channel.read(inBuf)) > 0) {
|
||||
System.out.println(myIndex + ": read " + count);
|
||||
}
|
||||
inBuf.flip();
|
||||
fos.write(inBuf.array(), inBuf.arrayOffset()+inBuf.position(), inBuf.remaining());
|
||||
inBuf.position(inBuf.limit());
|
||||
if (count < 0) {
|
||||
System.out.println(myIndex + ": Closing channel");
|
||||
fos.close();
|
||||
channel.close();
|
||||
}
|
||||
// dumpByteBuffer(myIndex, inBuf);
|
||||
inBuf.compact();
|
||||
}
|
||||
}
|
||||
|
||||
public void runMainLoop() throws Exception {
|
||||
boolean keepRunning = true;
|
||||
int port = 8988;
|
||||
ServerSocketChannel serverChannel = ServerSocketChannel.open();
|
||||
try {
|
||||
serverChannel.configureBlocking(false);
|
||||
serverChannel.socket().bind(new InetSocketAddress("0.0.0.0", port));
|
||||
Selector selector = Selector.open();
|
||||
serverChannel.register(selector, SelectionKey.OP_ACCEPT, null);
|
||||
while (keepRunning) {
|
||||
System.out.println("Running main loop");
|
||||
selector.select(10000);
|
||||
for (SelectionKey key : selector.selectedKeys()) {
|
||||
if (key.isAcceptable()) {
|
||||
System.out.println("Accepting new connection");
|
||||
SocketChannel c = ((ServerSocketChannel) key.channel()).accept();
|
||||
if (c != null) {
|
||||
c.configureBlocking(false);
|
||||
c.register(selector, SelectionKey.OP_READ, new Connection());
|
||||
}
|
||||
} else {
|
||||
SocketChannel c = (SocketChannel) key.channel();
|
||||
if (c.isOpen() && key.isReadable()) {
|
||||
Connection connection = (Connection)key.attachment();
|
||||
connection.handleRead(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
selector.selectedKeys().clear();
|
||||
}
|
||||
} finally {
|
||||
serverChannel.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
try {
|
||||
System.out.println("Starting server");
|
||||
if (args.length > 0) {
|
||||
new SendServer().runMainLoop();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user