view src/net/sourceforge/jsocks/UDPRelayServer.java @ 316:6b424bb783a2
ganymed
add ecdsa key support everywhere
author
Carl Byington <carl@five-ten-sg.com>
date
Wed, 30 Jul 2014 16:39:13 -0700 (2014-07-30)
parents
0ce5cc452d02
children
205ee2873330
line source
+ − package net.sourceforge.jsocks;
+ − import net.sourceforge.jsocks.server.*;
+ − import java.net.*;
+ − import java.io.*;
+ −
+ − /**
+ − UDP Relay server, used by ProxyServer to perform udp forwarding.
+ − */
+ − class UDPRelayServer implements Runnable {
+ −
+ −
+ − DatagramSocket client_sock;
+ − DatagramSocket remote_sock;
+ −
+ − Socket controlConnection;
+ −
+ − int relayPort;
+ − InetAddress relayIP;
+ −
+ − Thread pipe_thread1, pipe_thread2;
+ − Thread master_thread;
+ −
+ − ServerAuthenticator auth;
+ −
+ − long lastReadTime;
+ −
+ − static PrintStream log = null;
+ − static Proxy proxy = null;
+ − static int datagramSize = 0xFFFF;//64K, a bit more than max udp size
+ − static int iddleTimeout = 180000;//3 minutes
+ −
+ −
+ − /**
+ − Constructs UDP relay server to communicate with client
+ − on given ip and port.
+ − @param clientIP Address of the client from whom datagrams
+ − will be recieved and to whom they will be forwarded.
+ − @param clientPort Clients port.
+ − @param master_thread Thread which will be interrupted, when
+ − UDP relay server stoppes for some reason.
+ − @param controlConnection Socket which will be closed, before
+ − interrupting the master thread, it is introduced due to a bug
+ − in windows JVM which does not throw InterruptedIOException in
+ − threads which block in I/O operation.
+ − */
+ − public UDPRelayServer(InetAddress clientIP, int clientPort,
+ − Thread master_thread,
+ − Socket controlConnection,
+ − ServerAuthenticator auth)
+ − throws IOException {
+ − this.master_thread = master_thread;
+ − this.controlConnection = controlConnection;
+ − this.auth = auth;
+ − client_sock = new Socks5DatagramSocket(true, auth.getUdpEncapsulation(),
+ − clientIP, clientPort);
+ − relayPort = client_sock.getLocalPort();
+ − relayIP = client_sock.getLocalAddress();
+ −
+ − if (relayIP.getHostAddress().equals("0.0.0.0"))
+ − relayIP = InetAddress.getLocalHost();
+ −
+ − if (proxy == null)
+ − remote_sock = new DatagramSocket();
+ − else
+ − remote_sock = new Socks5DatagramSocket(proxy, 0, null);
+ − }
+ −
+ −
+ − //Public methods
+ − /////////////////
+ −
+ −
+ − /**
+ − Sets the timeout for UDPRelay server.<br>
+ − Zero timeout implies infinity.<br>
+ − Default timeout is 3 minutes.
+ − */
+ −
+ − static public void setTimeout(int timeout) {
+ − iddleTimeout = timeout;
+ − }
+ −
+ −
+ − /**
+ − Sets the size of the datagrams used in the UDPRelayServer.<br>
+ − Default size is 64K, a bit more than maximum possible size of the
+ − datagram.
+ − */
+ − static public void setDatagramSize(int size) {
+ − datagramSize = size;
+ − }
+ −
+ − /**
+ − Port to which client should send datagram for association.
+ − */
+ − public int getRelayPort() {
+ − return relayPort;
+ − }
+ − /**
+ − IP address to which client should send datagrams for association.
+ − */
+ − public InetAddress getRelayIP() {
+ − return relayIP;
+ − }
+ −
+ − /**
+ − Starts udp relay server.
+ − Spawns two threads of execution and returns.
+ − */
+ − public void start() throws IOException {
+ − remote_sock.setSoTimeout(iddleTimeout);
+ − client_sock.setSoTimeout(iddleTimeout);
+ − log("Starting UDP relay server on " + relayIP + ":" + relayPort);
+ − log("Remote socket " + remote_sock.getLocalAddress() + ":" +
+ − remote_sock.getLocalPort());
+ − pipe_thread1 = new Thread(this, "pipe1");
+ − pipe_thread2 = new Thread(this, "pipe2");
+ − lastReadTime = System.currentTimeMillis();
+ − pipe_thread1.start();
+ − pipe_thread2.start();
+ − }
+ −
+ − /**
+ − Stops Relay server.
+ − <p>
+ − Does not close control connection, does not interrupt master_thread.
+ − */
+ −
+ − public synchronized void stop() {
+ − master_thread = null;
+ − controlConnection = null;
+ − abort();
+ − }
+ −
+ − //Runnable interface
+ − ////////////////////
+ − public void run() {
+ − try {
+ − if (Thread.currentThread().getName().equals("pipe1"))
+ − pipe(remote_sock, client_sock, false);
+ − else
+ − pipe(client_sock, remote_sock, true);
+ − }
+ − catch (IOException ioe) {
+ − }
+ − finally {
+ − abort();
+ − log("UDP Pipe thread " + Thread.currentThread().getName() + " stopped.");
+ − }
+ − }
+ −
+ − //Private methods
+ − /////////////////
+ −
+ − private synchronized void abort() {
+ − if (pipe_thread1 == null) return;
+ −
+ − log("Aborting UDP Relay Server");
+ − remote_sock.close();
+ − client_sock.close();
+ −
+ − if (controlConnection != null)
+ − try { controlConnection.close();}
+ − catch (IOException ioe) {}
+ −
+ − if (master_thread != null) master_thread.interrupt();
+ −
+ − pipe_thread1.interrupt();
+ − pipe_thread2.interrupt();
+ − pipe_thread1 = null;
+ − }
+ −
+ −
+ − static private void log(String s) {
+ − if (log != null) {
+ − log.println(s);
+ − log.flush();
+ − }
+ − }
+ −
+ − private void pipe(DatagramSocket from, DatagramSocket to, boolean out)
+ − throws IOException {
+ − byte[] data = new byte[datagramSize];
+ − DatagramPacket dp = new DatagramPacket(data, data.length);
+ −
+ − while (true) {
+ − try {
+ − from.receive(dp);
+ − lastReadTime = System.currentTimeMillis();
+ −
+ − if (auth.checkRequest(dp, out))
+ − to.send(dp);
+ − }
+ − catch (UnknownHostException uhe) {
+ − log("Dropping datagram for unknown host");
+ − }
+ − catch (InterruptedIOException iioe) {
+ − //log("Interrupted: "+iioe);
+ − //If we were interrupted by other thread.
+ − if (iddleTimeout == 0) return;
+ −
+ − //If last datagram was received, long time ago, return.
+ − long timeSinceRead = System.currentTimeMillis() - lastReadTime;
+ −
+ − if (timeSinceRead >= iddleTimeout - 100) //-100 for adjustment
+ − return;
+ − }
+ −
+ − dp.setLength(data.length);
+ − }
+ − }
+ − }