org.redkalex.socks.SocksRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of redkale-plugins Show documentation
Show all versions of redkale-plugins Show documentation
Redkale-Plugins -- java framework
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkalex.socks;
import org.redkale.net.AsyncConnection;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.logging.*;
import org.redkale.util.ObjectPool;
/**
*
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public class SocksRunner implements Runnable {
private final AsyncConnection channel;
private final Logger logger;
private final boolean finest;
private final SocksContext context;
private final ObjectPool bufferPool;
private final byte[] bindAddressBytes;
private ByteBuffer buffer;
protected boolean closed = false;
private InetSocketAddress remoteAddress;
private AsyncConnection remoteChannel;
public SocksRunner(SocksContext context, ObjectPool bufferPool, AsyncConnection channel, final byte[] bindAddressBytes) {
this.context = context;
this.bufferPool = bufferPool;
this.logger = context.getLogger();
this.finest = this.context.getLogger().isLoggable(Level.FINEST);
this.channel = channel;
this.buffer = channel.pollReadBuffer();
this.bindAddressBytes = bindAddressBytes;
}
@Override
public void run() {
try {
ask();
} catch (Exception e) {
closeRunner(e);
}
}
private void ask() {
buffer.putChar((char) 0x0500);
buffer.flip();
this.channel.write(buffer, null, new CompletionHandler() {
@Override
public void completed(Integer result, Void attachment) {
if (buffer.hasRemaining()) {
channel.write(buffer, null, this);
return;
}
try {
connect();
} catch (Exception e) {
closeRunner(e);
}
}
@Override
public void failed(Throwable exc, Void attachment) {
closeRunner(exc);
}
});
}
private void connect() {
buffer.clear();
this.channel.setReadBuffer(buffer);
this.channel.read(new CompletionHandler() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
buffer.flip();
if (!buffer.hasRemaining()) {
closeRunner(null);
return;
}
if (buffer.getChar() != 0x0501) {
if (finest) logger.finest("connect header not 0x0501");
closeRunner(null);
return;
}
char addrtype = buffer.getChar(); //0x0001 - 4 ; 0x0003 - x ; 0x0004 - 16
try {
byte[] bytes = new byte[(addrtype == 0x0003) ? (buffer.get() & 0xff) : (addrtype * 4)];
buffer.get(bytes);
remoteAddress = new InetSocketAddress((addrtype == 0x0003) ? InetAddress.getByName(new String(bytes)) : InetAddress.getByAddress(bytes), buffer.getChar());
} catch (UnknownHostException e) {
failed(e, attachment);
return;
}
try {
remoteChannel = AsyncConnection.createTCP(bufferPool, context.getAsynchronousChannelGroup(), remoteAddress, 6, 6).join();
buffer.clear();
buffer.putChar((char) 0x0500);
buffer.put((byte) 0x00); //rsv
buffer.put(bindAddressBytes);
buffer.flip();
final ByteBuffer rbuffer = bufferPool.get();
final ByteBuffer wbuffer = bufferPool.get();
channel.write(buffer, null, new CompletionHandler() {
@Override
public void completed(Integer result, Void attachment) {
if (buffer.hasRemaining()) {
channel.write(buffer, null, this);
return;
}
stream();
}
@Override
public void failed(Throwable exc, Void attachment) {
bufferPool.accept(rbuffer);
bufferPool.accept(wbuffer);
closeRunner(exc);
}
});
} catch (Exception e) {
buffer.clear();
buffer.putChar((char) 0x0504);
if (finest) logger.log(Level.FINEST, remoteAddress + " remote connect error", e);
channel.write(buffer, null, new CompletionHandler() {
@Override
public void completed(Integer result, Void attachment) {
if (buffer.hasRemaining()) {
channel.write(buffer, null, this);
return;
}
closeRunner(null);
}
@Override
public void failed(Throwable exc, Void attachment) {
closeRunner(exc);
}
});
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
closeRunner(exc);
}
});
}
private void stream() {
new StreamCompletionHandler(channel, remoteChannel).completed(1, null);
new StreamCompletionHandler(remoteChannel, channel).completed(1, null);
}
public void closeRunner(final Throwable e) {
if (closed) return;
synchronized (this) {
if (closed) return;
closed = true;
try {
channel.close();
} catch (Throwable t) {
}
bufferPool.accept(buffer);
buffer = null;
if (e != null && finest) {
logger.log(Level.FINEST, "close socks channel by error", e);
}
}
}
private class StreamCompletionHandler implements CompletionHandler {
private final AsyncConnection readconn;
private final AsyncConnection writeconn;
private final ByteBuffer rbuffer;
public StreamCompletionHandler(AsyncConnection conn1, AsyncConnection conn2) {
this.readconn = conn1;
this.writeconn = conn2;
this.rbuffer = bufferPool.get();
this.rbuffer.flip();
}
@Override
public void completed(Integer result0, Void v0) {
final CompletionHandler self = this;
if (rbuffer.hasRemaining()) {
writeconn.write(rbuffer, v0, self);
return;
}
if (result0 < 1) {
self.failed(null, v0);
return;
}
rbuffer.clear();
readconn.setReadBuffer(rbuffer);
readconn.read(new CompletionHandler() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
if (result < 1) {
self.failed(null, v0);
return;
}
attachment.flip();
writeconn.write(attachment, v0, self);
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
self.failed(exc, v0);
}
});
}
@Override
public void failed(Throwable exc, Void v) {
bufferPool.accept(rbuffer);
readconn.dispose();
writeconn.dispose();
if (finest) logger.log(Level.FINEST, "StreamCompletionHandler closed", exc);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy