├── Start-NakovPortForwardingServer.cmd ├── start-nakov-port-forwarding-server.sh ├── NakovForwardServer.properties ├── ForwardThread.class ├── CheckAliveThread.class ├── NakovForwardServer.class ├── ForwardServerClientThread.class ├── NakovForwardServer$ServerDescription.class ├── LICENSE ├── ForwardThread.java ├── CheckAliveThread.java ├── README.md ├── ForwardServerClientThread.java └── NakovForwardServer.java /Start-NakovPortForwardingServer.cmd: -------------------------------------------------------------------------------- 1 | java NakovForwardServer 2 | -------------------------------------------------------------------------------- /start-nakov-port-forwarding-server.sh: -------------------------------------------------------------------------------- 1 | java NakovForwardServer 2 | -------------------------------------------------------------------------------- /NakovForwardServer.properties: -------------------------------------------------------------------------------- 1 | ListeningPort = 1522 2 | Servers = localhost:1521 3 | -------------------------------------------------------------------------------- /ForwardThread.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nakov/NakovForwardServer/HEAD/ForwardThread.class -------------------------------------------------------------------------------- /CheckAliveThread.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nakov/NakovForwardServer/HEAD/CheckAliveThread.class -------------------------------------------------------------------------------- /NakovForwardServer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nakov/NakovForwardServer/HEAD/NakovForwardServer.class -------------------------------------------------------------------------------- /ForwardServerClientThread.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nakov/NakovForwardServer/HEAD/ForwardServerClientThread.class -------------------------------------------------------------------------------- /NakovForwardServer$ServerDescription.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nakov/NakovForwardServer/HEAD/NakovForwardServer$ServerDescription.class -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2002 by Svetlin Nakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ForwardThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ForwardThread handles the TCP forwarding between a socket input stream (source) 3 | * and a socket output stream (destination). It reads the input stream and forwards 4 | * everything to the output stream. If some of the streams fails, the forwarding 5 | * is stopped and the parent thread is notified to close all its connections. 6 | */ 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.OutputStream; 11 | 12 | public class ForwardThread extends Thread 13 | { 14 | private static final int READ_BUFFER_SIZE = 8192; 15 | 16 | InputStream mInputStream = null; 17 | OutputStream mOutputStream = null; 18 | 19 | ForwardServerClientThread mParent = null; 20 | 21 | /** 22 | * Creates a new traffic forward thread specifying its input stream, 23 | * output stream and parent thread 24 | */ 25 | public ForwardThread(ForwardServerClientThread aParent, InputStream aInputStream, OutputStream aOutputStream) 26 | { 27 | mInputStream = aInputStream; 28 | mOutputStream = aOutputStream; 29 | mParent = aParent; 30 | } 31 | 32 | /** 33 | * Runs the thread. Until it is possible, reads the input stream and puts read 34 | * data in the output stream. If reading can not be done (due to exception or 35 | * when the stream is at his end) or writing is failed, exits the thread. 36 | */ 37 | public void run() 38 | { 39 | byte[] buffer = new byte[READ_BUFFER_SIZE]; 40 | try { 41 | while (true) { 42 | int bytesRead = mInputStream.read(buffer); 43 | if (bytesRead == -1) 44 | break; // End of stream is reached --> exit the thread 45 | mOutputStream.write(buffer, 0, bytesRead); 46 | } 47 | } catch (IOException e) { 48 | // Read/write failed --> connection is broken --> exit the thread 49 | } 50 | 51 | // Notify parent thread that the connection is broken and forwarding should stop 52 | mParent.connectionBroken(); 53 | } 54 | } -------------------------------------------------------------------------------- /CheckAliveThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * CheckAliveThread checks all dead servers in the server list and updates the 3 | * list when some dead server becomes alive. Checking is done on a beforehand 4 | * specified time itrervals. A server is considered alive if it accepts client 5 | * connections on the specified port. 6 | */ 7 | 8 | import java.io.IOException; 9 | import java.net.Socket; 10 | 11 | 12 | public class CheckAliveThread extends Thread 13 | { 14 | private NakovForwardServer mNakovForwardServer = null; 15 | 16 | /** 17 | * Creates a check alive thread. NakovForwardServer object is needed 18 | * for obtaining the servers list. 19 | */ 20 | public CheckAliveThread(NakovForwardServer aNakovForwardServer) 21 | { 22 | mNakovForwardServer = aNakovForwardServer; 23 | } 24 | 25 | /** 26 | * Until stopped checks all dead servers if they are alive and waits 27 | * specified time interval 28 | */ 29 | public void run() 30 | { 31 | while (!interrupted()) { 32 | try { 33 | Thread.sleep(mNakovForwardServer.getCheckAliveIntervalMs()); 34 | } catch (InterruptedException ie) { 35 | ie.printStackTrace(); 36 | } 37 | checkAllDeadServers(); 38 | } 39 | } 40 | 41 | /** 42 | * Checks all dead servers if they are alive and updates their state if needed. 43 | */ 44 | private void checkAllDeadServers() 45 | { 46 | NakovForwardServer.ServerDescription[] servers = mNakovForwardServer.getServersList(); 47 | for (int i=0; iTCP port forwarding software, written in Java: forwards local TCP port (e.g. 127.0.0.1:1521) to external network port (e.g. 0.0.0.0:1522). Works as reverse proxy server (like nginx) to tunnel a TCP connection through external port to an internal server+port in a local network. 3 | 4 | Nakov TCP Socket Forward Server - freeware 5 | Version 1.0 - March, 2002 6 | (c) 2001 by Svetlin Nakov - http://www.nakov.com 7 | 8 | Short decription: Nakov Forward Server is designed to forward (redirect) TCP connections from a client to a server choosen from a servers list. When a client is connected to Nakov Forward Server, a new connection is opened to some of the specified destination servers and all the traffic from destination server to Nakov Forward Server is redirected to the client and also all the traffic from 9 | the client to Nakov Forward Server is redirected to destination server. That way Nakov Forward Server makes transparent redirection of TCP connections. 10 | 11 | The TCP connection data transfer goes like this: 12 | 13 | CLIENT <--> NAKOV_FORWARD_SERVER <--> DESTINATION_SERVER 14 | 15 | Clients and destination servers communicate only with Nakov Forward Server. 16 | 17 | Typical usage scenario is to access an internal network resource from Internet by TCP port forwarding: 18 | 19 | Internet IP <--> NakovForwardServer <--> Internal network IP 20 | (e.g. 62.176.119.226) (e.g. 212.50.7.153:8888) (e.g. 192.168.1.117:80) 21 | 22 | Nakov Forward Server supports failt tolerance. When some of the servers in the list fail to respond to TCP connect request (dead server), Nakov Forward Server tries the next server in the list until it finds alive server. All dead servers are checked if they are alive through some time interval and when some server becomes available, it is added to alive list. When no server is alive, no connection will be established. 23 | 24 | Nakov Forward Server supports also load balancing features. If load balancing is enabled, when a client connection is accepted, Nakov Forward Server will redirect the client to the least loaded server from the servers list. We consider the server which hast minimal alive connections established by Nakov Forward Server is least loaded. 25 | 26 | # Benefits of Using Nakov Forward Server? 27 | 28 | - Destination server does not know the real IP of the client. It thinks that the IP of Nakov Forward Server is its client. Thus we can use a server licensed for one IP address on several machines simultaneously. 29 | 30 | - Nakov Forward Server can run on a port number that is allowed by the firewall and forward to a port number that is not allowed by firewall. Thus, started on a server in a local network, it can give access to some disabled by the firewall services. 31 | 32 | - Nakov Forward Server can give access to multiple clients to some service that is allowed only for some fixed IP address when started on the machine with this IP. 33 | 34 | - Fault Tolerance (failover) of Nakov Forward Server helps to avoid faults when some of the servers die. Of course there is special hardware for this, but it has high price. Instead you can use Nakov Forward Server (that is free). If you setup several Nakov Forward Servers configured to use the same set of destination servers and if you configure your routers to use redirect traffic to both servers, you will obtain a stable fault tolerance system. In such a system you have guarantee that crash of any of the servers (including some of the Nakov Forward Servers) will not stop the service that these servers provide. Of course the destination servers should run in a cluster and replicate their sessions. 35 | 36 | - Load balancing helps to avoid overloading of the servers by distributing the clients between them. Of course this should be done by special hardware called "load balancer", but if we don't have such hardware, we can still use this technology. When we use load balancing, all the servers in the list should be running in a cluster and there should be no matter what of the servers the client is connected to. The servers should communicate each other and replicate their session data. 37 | 38 | # Configuration 39 | 40 | NakovForwardServer.properties configuration file contains all the settings of Nakov Forward Server. The only mandatory field is "Servers". Destination servers should be described in following format: 41 | 42 | Servers = server1:port1, server2:port2, server3:port3, ... 43 | 44 | For example: 45 | 46 | Servers = 192.168.0.22:80, rakiya:80, 192.168.0.23:80, www.nakov.com:80 47 | 48 | Nakov Forward Server listening port should be in format: 49 | 50 | ListeningPort = some_port (in range 1-65535) 51 | 52 | Check alive interval through which all dead threads should be re-checked if they are alive is specified by following line: 53 | 54 | CheckAliveInterval = time_interval (in milliseconds) 55 | 56 | Using load balancing algorithm is specified by following line: 57 | 58 | LoadBalancing = Yes/No 59 | 60 | # Compilation 61 | 62 | javac *.java 63 | 64 | # Running the server 65 | 66 | java NakovForwardServer 67 | 68 | # ngrok 69 | Finally, if you have more advanced needs, you might find this localhost tunelling software useful: https://ngrok.com 70 | -------------------------------------------------------------------------------- /ForwardServerClientThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ForwardServerClientThread handles the clients of Nakov Forward Server. It 3 | * finds suitable server from the server pool, connects to it and starts 4 | * the TCP forwarding between given client and its assigned server. After 5 | * the forwarding is failed and the two threads are stopped, closes the sockets. 6 | */ 7 | 8 | import java.net.Socket; 9 | import java.net.SocketException; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.io.OutputStream; 13 | 14 | public class ForwardServerClientThread extends Thread 15 | { 16 | private NakovForwardServer mNakovForwardServer = null; 17 | private NakovForwardServer.ServerDescription mServer = null; 18 | private Socket mClientSocket = null; 19 | private Socket mServerSocket = null; 20 | private boolean mBothConnectionsAreAlive = false; 21 | private String mClientHostPort; 22 | private String mServerHostPort; 23 | 24 | /** 25 | * Creates a client thread for handling clients of NakovForwardServer. 26 | * A client socket should be connected and passed to this constructor. 27 | * A server socket is created later by run() method. 28 | */ 29 | public ForwardServerClientThread(NakovForwardServer aNakovForwardServer, Socket aClientSocket) 30 | { 31 | mNakovForwardServer = aNakovForwardServer; 32 | mClientSocket = aClientSocket; 33 | } 34 | 35 | /** 36 | * Obtains a destination server socket to some of the servers in the list. 37 | * Starts two threads for forwarding : "client in <--> dest server out" and 38 | * "dest server in <--> client out", waits until one of these threads stop 39 | * due to read/write failure or connection closure. Closes opened connections. 40 | */ 41 | public void run() 42 | { 43 | try { 44 | mClientHostPort = mClientSocket.getInetAddress().getHostAddress() + ":" + mClientSocket.getPort(); 45 | 46 | // Create a new socket connection to one of the servers from the list 47 | mServerSocket = createServerSocket(); 48 | if (mServerSocket == null) { // If all the servers are down 49 | System.out.println("Can not establish connection for client " + 50 | mClientHostPort + ". All the servers are down."); 51 | try { mClientSocket.close(); } catch (IOException e) {} 52 | return; 53 | } 54 | 55 | // Obtain input and output streams of server and client 56 | InputStream clientIn = mClientSocket.getInputStream(); 57 | OutputStream clientOut = mClientSocket.getOutputStream(); 58 | InputStream serverIn = mServerSocket.getInputStream(); 59 | OutputStream serverOut = mServerSocket.getOutputStream(); 60 | 61 | mServerHostPort = mServer.host + ":" + mServer.port; 62 | mNakovForwardServer.log("TCP Forwarding " + mClientHostPort + " <--> " + mServerHostPort + " started."); 63 | 64 | // Start forwarding of socket data between server and client 65 | ForwardThread clientForward = new ForwardThread(this, clientIn, serverOut); 66 | ForwardThread serverForward = new ForwardThread(this, serverIn, clientOut); 67 | mBothConnectionsAreAlive = true; 68 | clientForward.start(); 69 | serverForward.start(); 70 | 71 | } catch (IOException ioe) { 72 | ioe.printStackTrace(); 73 | } 74 | } 75 | 76 | /** 77 | * connectionBroken() method is called by forwarding child threads to notify 78 | * this thread (their parent thread) that one of the connections (server or client) 79 | * is broken (a read/write failure occured). This method disconnects both server 80 | * and client sockets causing both threads to stop forwarding. 81 | */ 82 | public synchronized void connectionBroken() 83 | { 84 | if (mBothConnectionsAreAlive) { 85 | // One of the connections is broken. Close the other connection and stop forwarding 86 | // Closing these socket connections will close their input/output streams 87 | // and that way will stop the threads that read from these streams 88 | try { mServerSocket.close(); } catch (IOException e) {} 89 | try { mClientSocket.close(); } catch (IOException e) {} 90 | 91 | mBothConnectionsAreAlive = false; 92 | mServer.clientsConectedCount--; 93 | 94 | mNakovForwardServer.log("TCP Forwarding " + mClientHostPort + " <--> " + mServerHostPort + " stopped."); 95 | } 96 | } 97 | 98 | /** 99 | * @return a new socket connected to some of the servers in the destination 100 | * servers list. Sequentially a connection to the least loaded server from 101 | * the list is tried to be established. If connecting to some alive server 102 | * fail, this server it marked as dead and next alive server is tried. If all 103 | * the servers are dead, null is returned. Thus if at least one server is alive, 104 | * a connection will be established (of course after some delay) and the system 105 | * will not fail (it is fault tolerant). Dead servers can be marked as alive if 106 | * revived, but this is done later by check alive thread. 107 | */ 108 | private Socket createServerSocket() throws IOException 109 | { 110 | while (true) { 111 | mServer = getServerWithMinimalLoad(); 112 | if (mServer == null) // All the servers are down 113 | return null; 114 | try { 115 | Socket socket = new Socket(mServer.host, mServer.port); 116 | mServer.clientsConectedCount++; 117 | return socket; 118 | } catch (IOException ioe) { 119 | mServer.isAlive = false; 120 | } 121 | } 122 | } 123 | 124 | /** 125 | * @return the least loaded alive server from the server list if load balancing 126 | * is enabled or first alive server from the list if load balancing algorithm is 127 | * disabled or null if all the servers in the list are dead. 128 | */ 129 | private NakovForwardServer.ServerDescription getServerWithMinimalLoad() 130 | { 131 | NakovForwardServer.ServerDescription minLoadServer = null; 132 | NakovForwardServer.ServerDescription[] servers = mNakovForwardServer.getServersList(); 133 | for (int i=0; i NAKOV_FORWARD_SERVER <--> DESTINATION_SERVER 16 | * 17 | * Clients and Destination Servers communicate only with Nakov Forward Server. 18 | * 19 | * Nakov Forward Server supports failt tolerance. When some of the servers in the 20 | * list fail to respond to TCP connect request (dead server), Nakov Forward Server 21 | * tries the next server in the list until it finds alive server. All dead servers 22 | * are checked if they are alive through some time interval and when some server 23 | * becomes available, it is added to alive list. When no server is alive, no 24 | * connection will be established. 25 | * 26 | * Nakov Forward Server supports also load balancing features. If load balancing 27 | * is enabled, when a client connection is accepted, Nakov Forward Server will 28 | * redirect the client to the least loaded server from the servers list. We consider 29 | * the server which hast minimal alive connections established by Nakov Forward 30 | * Server is least loaded. 31 | * 32 | * What we gain when we use Nakov Proxy Server? 33 | * - Destination server does not know the real IP of the client. It thinks 34 | * that the IP of Nakov Forward Server is its client. Thus we can use a server 35 | * licensed for one IP address on several machines simultaneously. 36 | * - Nakov Forward Server can run on a port number that is allowed by the 37 | * firewall and forward to a port number that is not allowed by firewall. Thus, 38 | * started on a server in a local network, it can give access to some disabled 39 | * by the firewall services. 40 | * - Nakov Forward Server can give access to multiple clients to some service 41 | * that is allowed only for some fixed IP address when started on the machine 42 | * with this IP. 43 | * - Fault Tolerance (failover) of Nakov Forward Server helps to avoid faults 44 | * when some of the servers die. Of course there is special hardware for this, but 45 | * it has high price. Instead you can use Nakov Forward Server (that is free). 46 | * If you setup several Nakov Forward Servers configured to use the same set of 47 | * destination servers and if you configure your routers to use redirect traffic 48 | * to both servers, you will obtain a stable fault tolerance system. In such a 49 | * system you have guarantee that crash of any of the servers (including some of 50 | * the Nakov Forward Servers) will not stop the service that these servers provide. 51 | * Of course the destination servers should run in a cluster and replicate their 52 | * sessions. 53 | * - Load balancing helps to avoid overloading of the servers by distributing 54 | * the clients between them. Of course this should be done by special hardware 55 | * called "load balancer", but if we don't have such hardware, we can still use 56 | * this technology. When we use load balancing, all the servers in the list should 57 | * be running in a cluster and there should be no matter what of the servers the 58 | * client is connected to. The servers should communicate each other and replicate 59 | * their session data. 60 | * 61 | * NakovForwardServer.properties configuration file contains all the settings of 62 | * Nakov Forward Server. The only mandatory field is "Servers" 63 | * Destination servers should be in following format: 64 | * Servers = server1:port1, server2:port2, server3:port3, ... 65 | * For example: 66 | * Servers = 192.168.0.22:80, rakiya:80, 192.168.0.23:80, www.nakov.com:80 67 | * Nakov Forward Server listening port should be in format: 68 | * ListeningPort = some_port (in range 1-65535) 69 | * Using load balancing algorithm is specified by following line: 70 | * LoadBalancing = Yes/No 71 | * Check alive interval through which all dead threads should be re-checked if 72 | * they are alive is specified by following line: 73 | * CheckAliveInterval = time_interval (in milliseconds) 74 | */ 75 | 76 | import java.util.ArrayList; 77 | import java.net.ServerSocket; 78 | import java.net.Socket; 79 | import java.net.InetAddress; 80 | import java.io.IOException; 81 | import java.io.FileInputStream; 82 | import java.util.Properties; 83 | import java.util.StringTokenizer; 84 | 85 | public class NakovForwardServer 86 | { 87 | private static final boolean ENABLE_LOGGING = true; 88 | public static final String SETTINGS_FILE_NAME = "NakovForwardServer.properties"; 89 | 90 | private ServerDescription[] mServersList = null; 91 | private int mListeningTcpPort = 2001; 92 | private boolean mUseLoadBalancingAlgorithm = true; 93 | private long mCheckAliveIntervalMs = 5*1000; 94 | 95 | /** 96 | * ServerDescription descripts a server (server hostname/IP, server port, 97 | * is the server alive at last check, how many clients are connected to it, etc.) 98 | */ 99 | class ServerDescription 100 | { 101 | public String host; 102 | public int port; 103 | public int clientsConectedCount = 0; 104 | public boolean isAlive = true; 105 | public ServerDescription(String host, int port) 106 | { 107 | this.host = host; 108 | this.port = port; 109 | } 110 | } 111 | 112 | /** 113 | * @return an array of ServerDescription - all destination servers. 114 | */ 115 | public ServerDescription[] getServersList() 116 | { 117 | return mServersList; 118 | } 119 | 120 | /** 121 | * @return the time interval (in milliseconds) through which all dead servers 122 | * should be re-checked if they are alive (a server is alive if accepts 123 | * client connections on the specified port, otherwise is dead). 124 | */ 125 | public long getCheckAliveIntervalMs() 126 | { 127 | return mCheckAliveIntervalMs; 128 | } 129 | 130 | /** 131 | * @return true if load balancing algorithm is enabled. 132 | */ 133 | public boolean isLoadBalancingEnabled() 134 | { 135 | return mUseLoadBalancingAlgorithm; 136 | } 137 | 138 | /** 139 | * Reads the Nakov Forward Server configuration file "NakovForwardServer.properties" 140 | * and load user preferences. This method is called once during the server startup. 141 | */ 142 | public void readSettings() 143 | throws Exception 144 | { 145 | // Read properties file in a Property object 146 | Properties props = new Properties(); 147 | props.load(new FileInputStream(SETTINGS_FILE_NAME)); 148 | 149 | // Read and parse the server list 150 | String serversProperty = props.getProperty("Servers"); 151 | if (serversProperty == null ) 152 | throw new Exception("The server list can not be empty."); 153 | try { 154 | ArrayList servers = new ArrayList(); 155 | StringTokenizer stServers = new StringTokenizer(serversProperty,","); 156 | while (stServers.hasMoreTokens()) { 157 | String serverAndPort = stServers.nextToken().trim(); 158 | StringTokenizer stServerPort = new StringTokenizer(serverAndPort,": "); 159 | String host = stServerPort.nextToken(); 160 | int port = Integer.parseInt(stServerPort.nextToken()); 161 | servers.add(new ServerDescription(host,port)); 162 | } 163 | mServersList = (ServerDescription[]) servers.toArray(new ServerDescription[] {}); 164 | } catch (Exception e) { 165 | throw new Exception("Invalid server list format : " + serversProperty); 166 | } 167 | if (mServersList.length == 0) 168 | throw new Exception("The server list can not be empty."); 169 | 170 | // Read server's listening port number 171 | try { 172 | mListeningTcpPort = Integer.parseInt(props.getProperty("ListeningPort")); 173 | } catch (Exception e) { 174 | log("Server listening port not specified. Using default port : " + mListeningTcpPort); 175 | } 176 | 177 | // Read load balancing property 178 | try { 179 | String loadBalancing = props.getProperty("LoadBalancing").toLowerCase(); 180 | mUseLoadBalancingAlgorithm = (loadBalancing.equals("yes") || 181 | loadBalancing.equals("true") || loadBalancing.equals("1") || 182 | loadBalancing.equals("enable") || loadBalancing.equals("enabled")); 183 | } catch (Exception e) { 184 | log("LoadBalancing property is not specified. Using default value : " + mUseLoadBalancingAlgorithm); 185 | } 186 | 187 | // Read the check alive interval 188 | try { 189 | mCheckAliveIntervalMs = Integer.parseInt(props.getProperty("CheckAliveInterval")); 190 | } catch (Exception e) { 191 | log("Check alive interval is not specified. Using default value : " + mCheckAliveIntervalMs + " ms."); 192 | } 193 | 194 | } 195 | 196 | /** 197 | * Starts a thread that re-checks all dead threads if they are alive 198 | * through mCheckAliveIntervalMs millisoconds 199 | */ 200 | private void startCheckAliveThread() 201 | { 202 | CheckAliveThread checkAliveThread = new CheckAliveThread(this); 203 | checkAliveThread.setDaemon(true); 204 | checkAliveThread.start(); 205 | } 206 | 207 | /** 208 | * Starts the forward server - binds on a given port and starts serving 209 | */ 210 | public void startForwardServer() 211 | throws Exception 212 | { 213 | // Bind server on given TCP port 214 | ServerSocket serverSocket; 215 | try { 216 | serverSocket = new ServerSocket(mListeningTcpPort); 217 | } catch (IOException ioe) { 218 | throw new IOException("Unable to bind to port " + mListeningTcpPort); 219 | } 220 | 221 | log("Nakov Forward Server started on TCP port " + mListeningTcpPort + "."); 222 | log("All TCP connections to " + InetAddress.getLocalHost().getHostAddress() + 223 | ":" + mListeningTcpPort + " will be forwarded to the following servers:"); 224 | for (int i=0; i