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