import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class UdpProxy
{
public static void main(String[] args) throws Exception
{
boolean testMode = args.length == 0;
String serverHost;
int serverPort;
int proxyPort;
if (args.length != 3 && !testMode)
{
System.out.println("Use: java UdpProxy <serverhost> <serverport> <proxyport>");
return;
}
if (!testMode)
{
serverHost = args[0];
serverPort = Integer.parseInt(args[1]);
proxyPort = Integer.parseInt(args[2]);
}
else
{
serverHost = "192.168.1.114";
serverPort = 19132;
proxyPort = 19133;
}
new UdpProxy(serverHost, serverPort, proxyPort).runServer();
}
static final int CONNECTION_TIMEOUT = 60000;
HashMap<InetSocketAddress, ChannelInfo> channelMap = new HashMap<InetSocketAddress, ChannelInfo>();
InetSocketAddress serverAddress;
int proxyPort;
public UdpProxy(String serverHost, int serverPort, int proxyPort) throws Exception
{
InetAddress resolvedAddress = InetAddress.getByName(serverHost);
this.serverAddress = new InetSocketAddress(resolvedAddress, serverPort);
this.proxyPort = proxyPort;
}
public void runServer() throws Exception
{
System.out.println("Listening on " + proxyPort + ", forwarding to " + serverAddress);
ByteBuffer buff = ByteBuffer.allocate(1024*1024); //this is probably more than necessary
Selector selector = Selector.open();
DatagramChannel proxyChannel = addChannel(selector, proxyPort);
long connectionTestTime = System.currentTimeMillis();
while (true)
{
try
{
selector.select(10000); //selector.selectNow();
Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
while (keyIterator.hasNext())
{
SelectionKey key = keyIterator.next();
keyIterator.remove();
if (key.isReadable())
{
DatagramChannel currentChannel = (DatagramChannel) key.channel();
InetSocketAddress localAddress = (InetSocketAddress) currentChannel.socket().getLocalSocketAddress();
buff.clear();
InetSocketAddress remoteAddress = (InetSocketAddress) currentChannel.receive(buff);
buff.flip();
if (!fromServer(remoteAddress))
{
ChannelInfo info = channelMap.get(remoteAddress);
if (info == null)
{
DatagramChannel tempChannel = addChannel(selector, serverAddress);
InetSocketAddress tempAddress = (InetSocketAddress) tempChannel.socket().getLocalSocketAddress();
info = new ChannelInfo(tempChannel, remoteAddress);
channelMap.put(remoteAddress, info);
System.out.println("Added key = " + remoteAddress.toString());
channelMap.put(tempAddress, info);
System.out.println("Added key = " + tempAddress.toString());
}
info.rxTime = System.currentTimeMillis();
info.channel.send(buff, serverAddress);
}
else
{
ChannelInfo info = channelMap.get(localAddress);
if (info != null)
{
proxyChannel.send(buff, info.remoteAddress);
}
}
}
}
//Test & remove old connections
if (System.currentTimeMillis() - connectionTestTime >= CONNECTION_TIMEOUT)
{
connectionTestTime = System.currentTimeMillis();
Iterator<Map.Entry<InetSocketAddress, ChannelInfo>> entryIterator = channelMap.entrySet().iterator();
while (entryIterator.hasNext())
{
Map.Entry<InetSocketAddress, ChannelInfo> entry = entryIterator.next();
InetSocketAddress address = entry.getKey();
ChannelInfo info = entry.getValue();
if (connectionTestTime - info.rxTime >= CONNECTION_TIMEOUT)
{
info.channel.close();
entryIterator.remove();
System.out.println("Removed key = " + address.toString());
}
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
public boolean fromServer(InetSocketAddress address)
{
return address.getAddress().equals(serverAddress.getAddress());
}
public DatagramChannel addChannel(Selector selector, int bindPort) throws Exception
{
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(bindPort));
channel.register(selector, SelectionKey.OP_READ);
return channel;
}
public DatagramChannel addChannel(Selector selector, InetSocketAddress address) throws Exception
{
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(false);
channel.connect(address);
channel.register(selector, SelectionKey.OP_READ);
return channel;
}
public static class ChannelInfo
{
public ChannelInfo()
{
}
public ChannelInfo(DatagramChannel channel, InetSocketAddress remoteAddress)
{
this.channel = channel;
this.localAddress = (InetSocketAddress) channel.socket().getLocalSocketAddress();
this.remoteAddress = remoteAddress;
}
DatagramChannel channel;
InetSocketAddress localAddress;
InetSocketAddress remoteAddress;
long rxTime;
}
}
Saturday, October 26, 2013
UDP Proxy / Minecraft PE Proxy
Here is a UDP Proxy implemented in Java that can be used for Minecraft Pocket Edition. Inspired by the Node.js implementation. Runs great on Raspberry Pi.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment