
astra.debugger.DebuggerClient Maven / Gradle / Ivy
package astra.debugger;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class DebuggerClient implements Runnable {
private List pendingChanges = new LinkedList();
private Map> pendingData = new HashMap>();
private Map rspHandlers = (Map) Collections.synchronizedMap(new HashMap());
private Selector selector;
private ByteBuffer readBuffer = ByteBuffer.allocate(8192);
private InetAddress host = null;
private int port;
public DebuggerClient(String host, int port) throws IOException {
this.host = InetAddress.getByName(host);
this.port = port;
selector = initSelector();
}
private Selector initSelector() throws IOException {
return SelectorProvider.provider().openSelector();
}
private SocketChannel initiateConnection() throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(this.host, this.port));
synchronized (this.pendingChanges) {
this.pendingChanges.add(new ChangeRequest(socketChannel, ChangeRequest.REGISTER, SelectionKey.OP_CONNECT));
}
return socketChannel;
}
private void finishConnection(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
try {
socketChannel.finishConnect();
} catch (IOException e) {
e.printStackTrace();
key.cancel();
return;
}
// Register an interest in writing on this channel
key.interestOps(SelectionKey.OP_WRITE);
}
public void run() {
while (true) {
try {
// Process any pending changes
synchronized (this.pendingChanges) {
Iterator changes = this.pendingChanges.iterator();
while (changes.hasNext()) {
ChangeRequest change = changes.next();
switch (change.type) {
case ChangeRequest.CHANGEOPS:
SelectionKey key = change.socket.keyFor(this.selector);
key.interestOps(change.ops);
break;
case ChangeRequest.REGISTER:
change.socket.register(this.selector, change.ops);
break;
}
}
this.pendingChanges.clear();
}
selector.select();
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey key = selectedKeys.next();
selectedKeys.remove();
if (!key.isValid())
continue;
if (key.isConnectable()) {
this.finishConnection(key);
} else if (key.isReadable()) {
read(key);
} else if (key.isWritable()) {
this.write(key);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void read(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
readBuffer.clear();
int bytesRead;
try {
bytesRead = socketChannel.read(readBuffer);
} catch (IOException e) {
key.cancel();
socketChannel.close();
return;
}
if (bytesRead == -1) {
key.channel().close();
key.cancel();
return;
}
this.handleResponse(socketChannel, this.readBuffer.array(), bytesRead);
}
private void handleResponse(SocketChannel socketChannel, byte[] data, int numRead) throws IOException {
// Make a correctly sized copy of the data before handing it
// to the client
byte[] rspData = new byte[numRead];
System.arraycopy(data, 0, rspData, 0, numRead);
// Look up the handler for this channel
DebuggerHandler handler = this.rspHandlers.get(socketChannel);
// And pass the response to it
if (handler.handleResponse(rspData)) {
// The handler has seen enough, close the connection
socketChannel.close();
socketChannel.keyFor(this.selector).cancel();
}
}
private void write(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
synchronized (this.pendingData) {
List queue = this.pendingData.get(socketChannel);
while (!queue.isEmpty()) {
ByteBuffer buf = (ByteBuffer) queue.get(0);
socketChannel.write(buf);
if (buf.remaining() > 0) {
break;
}
queue.remove(0);
}
if (queue.isEmpty()) {
key.interestOps(SelectionKey.OP_READ);
}
}
}
public void send(byte[] data, DebuggerHandler handler) throws IOException {
SocketChannel socket = this.initiateConnection();
this.rspHandlers.put(socket, handler);
synchronized (this.pendingData) {
List queue = this.pendingData.get(socket);
if (queue == null) {
queue = new ArrayList();
this.pendingData.put(socket, queue);
}
queue.add(ByteBuffer.wrap(data));
}
this.selector.wakeup();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy