/Users/lyon/j4p/src/net/web/PortMap.java
|
1 /**
2 * Created by IntelliJ IDEA.
3 * User: dlyon
4 * Date: Nov 19, 2003
5 * Time: 1:16:43 PM
6 * To change this template use Options | File Templates.
7 */
8 package net.web;
9
10 //
11 // Genaral puporse IP:port forwarder device
12 // (c) RJHM van den Bergh/comweb.nl
13 // support@comweb.nl
14 //
15 // DISCLAIMER: The use of this software is at your own risk.
16 //
17 // Purpose to change it later to a conditonal tunneling device
18 // I've configured a local http server to listen to port 80 except on one IP address.
19 // I run this port forwarding device on this IP address.
20 // So for the browser it just looks if he connects to this http server.
21 //
22 // Later on I can add some heuristic algoritme to determine so an applet can request a http tunnel.
23 // For example a chat applet.
24 // This way it can bypass proxy firewalls.
25 //
26 // COPYRIGHT:
27 // Freeware but at own risk.
28 //
29
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.InterruptedIOException;
33 import java.io.OutputStream;
34 import java.net.InetAddress;
35 import java.net.ServerSocket;
36 import java.net.Socket;
37
38 public class PortMap implements Runnable {
39 private static Thread serverSocketThread;
40 // main thread (for ServerSocket)
41 private Thread serverListenerThread;
42 private Thread clientListenerThread;
43 // threads used to handle seperate connections
44 private Socket clientSocket;
45 // socket to the client
46 private Socket serverSocket;
47 // socket to the server
48 private InputStream clientInputStream;
49 // Data from the client
50 private InputStream serverInputStream;
51 // Data from the server
52 private OutputStream clientOutputStream;
53 // Data to the client;
54 private OutputStream serverOutputStream;
55 // Data to the server;
56 private boolean connectionErrorFlag = false;
57 // flag indicating that a (connection) error occured
58 private static final int S0_TIMEOUT = 25000;
59 // timout 25 seconds, if nothing heard for 25 second
60 //then the connection is considered lost
61
62 private String client_line = "";
63 // for debuging
64
65 private static ServerSocket mainSocket;
66 // main socket for new connections
67 private static final int BACKLOG = 15;
68 // Max number of waiting connections
69
70 private static final int OUT_PORT
71 = 8086;
72 // sends output to port 80
73 private static final String OUTPUT_ADDRESS_STRING
74 = "show.docjava.com";
75 // to localhost
76
77 private static final int INPUT_PORT = 80;
78 // listens to port 80
79
80 private static final String INPUT_ADDRESS_STRING
81 = "localhost";
82 // listens on this this IP
83 private static InetAddress in_address;
84 // filled in later with the above IP
85
86 public PortMap() {
87 super();
88
89 // create blanc object
90 serverSocketThread = new Thread(this);
91 // create main thread
92 serverSocketThread.start();
93 // start main thread (listen for new connections)
94 }
95
96 public PortMap(Socket socket) throws IOException {
97 clientSocket = socket;
98 // store socket
99 clientSocket.setSoTimeout(S0_TIMEOUT);
100 // set timeout to prevent connections clogging up the server
101 clientInputStream = clientSocket.getInputStream();
102 // get the stream from the client
103 clientOutputStream = clientSocket.getOutputStream();
104 // get the stream to the client
105
106 serverSocket = new Socket(
107 InetAddress.getByName(OUTPUT_ADDRESS_STRING),
108 OUT_PORT);
109 // create socket to the server
110 serverSocket.setSoTimeout(S0_TIMEOUT);
111 // set timeout to prevent connections clogging up
112 //the server
113 serverInputStream = serverSocket.getInputStream();
114 // get the stream from the server
115 serverOutputStream = serverSocket.getOutputStream();
116 // get the stream to the server
117
118 clientListenerThread = new Thread(this);
119 // create thread that handles client data
120 serverListenerThread = new Thread(this);
121 // create thread that handles server data
122 clientListenerThread.start();
123 // start client thread
124 serverListenerThread.start();
125 // start server thread
126 }
127
128 public static void main(String arg[]) {
129 try {
130 net.proxy.Proxy.setSoeProxy();
131 in_address = InetAddress.getByName(INPUT_ADDRESS_STRING); // fill in the IP number where to listen to.
132 mainSocket = new ServerSocket(INPUT_PORT, BACKLOG, in_address); // create the server socket
133 new PortMap(); // create (and start) the porter application
134 } catch (Exception e) {
135 System.out.println("Oops couldnt start"); // Perhaps a bind exception if IP:port already in use.
136 e.printStackTrace(); // print some more debuging information.
137 }
138 }
139
140 public void run() {
141 while (Thread.currentThread() == serverSocketThread) // loop the main thread for ever (if it is the main thread)
142 {
143 try {
144 new PortMap(mainSocket.accept()); // wait for incomming connections and then start an new porter object (with its own threads) to handle the connection further
145 } catch (Exception e) {
146 System.out.println("Oops error."); // unwanted error, perhaps caused by the client.
147 e.printStackTrace(); // print more debugging information
148 }
149 Thread.yield(); // always yield at a while loop so it can't consume all processor power
150 }
151
152 while (Thread.currentThread() == clientListenerThread) // if its the thread listening to a client the loop it
153 {
154 byte[] data = new byte[1];
155 try {
156 data[0] = (byte) clientInputStream.read();
157
158 /*
159 //
160 // Conditional forwarding can be added here
161 // It can be done with some heuristic algorithm
162 //
163 */
164
165 /*
166 //
167 // To output client data to the console
168 // Note this enormously slows down the forwarding !!
169 //
170 if (data[0]!=10) // \n in default encoding
171 {
172 client_line=client_line+new String(data);
173 } else
174 {
175 System.out.println("Client: "+client_line);
176 client_line="";
177 }
178 //
179 // or easier System.out.write(data[0]);
180 //
181 */
182
183 serverOutputStream.write(data[0]);
184 // forward the data to the server
185 } catch (InterruptedIOException ie)
186 // catch a timeout exception on the client side
187 {
188 System.out.println("Client time out!!");
189 // says enough I think, not that this will not be uncommen
190 connectionErrorFlag = true;
191 // set flag to indicate that an error occured
192 } catch (Exception e) {
193 System.out.println("Oops Error client_listener"); // Catch any other error
194 e.printStackTrace(); // output additional debuging info but note that this error is most likely related to some network thing so not very uncommen
195 connectionErrorFlag = true; // set error flag so we know forwardign isn't usefull anymore.
196 } finally {
197 Thread.yield(); // always yield a while loop so it never consumes all processor power
198 if (connectionErrorFlag) {
199 close();
200 return;
201 }
202 // check for error and if needed call the close() method of this class instance
203 }
204 }
205
206 while (Thread.currentThread() == serverListenerThread)
207 // if it is the thread listening the server then loop it
208 {
209 byte data;
210 // variable to store data into (byte data)
211 try {
212 data = (byte) serverInputStream.read();
213 // get (response) data from the server
214 clientOutputStream.write(data);
215 // forward it to the client
216 } catch (InterruptedIOException ie)
217
218 // catch any timeouts from the server
219 //(prevents server from being clogged with unused connections)
220 {
221 System.out.println("Server time out!!"); // says enough
222 connectionErrorFlag = true; // set error flag to indicate that forwarding isn't useful anymore
223 } catch (Exception e) {
224 System.out.println("Oops Error Server_listener"); // Says enough some error occured which isn't uncommen esspecially when its an IO erro
225 e.printStackTrace(); // output additional debugging information
226 connectionErrorFlag = true; // set error flag
227 } finally {
228 Thread.yield(); // allways yield a while loop, to prevent it using up all processor power
229 if (connectionErrorFlag) {
230 close();
231 return;
232 } // if an error has ocurred call the close() method from this class instance
233 }
234 }
235 }
236
237 private void close() {
238 try {
239 if (clientInputStream != null) // check if the stream coming from the the client does exist
240 closeStreamFromClient();
241 } catch (IOException e) {
242 System.out.println("Couldn't close stream from client"); // Wierd thing the stream wouldn't close.
243 e.printStackTrace(); // output additional debugging info
244 }
245
246 try {
247 if (serverInputStream != null) // check if the stream coming from the server exist
248 closeStreamToServer();
249 } catch (IOException e) {
250 System.out.println("Couldnt close stream to server"); // Wierd thing, the stream wouldn't close
251 e.printStackTrace(); // output additional debuging information.
252 }
253
254 try {
255 if (clientSocket != null) // check if the socket to the client exist
256 closeSocketToClient();
257 } catch (IOException e) {
258 System.out.println("Couldn't close socket to client."); // A wierd error occured we couldn't close the socket to the client
259 e.printStackTrace(); // Output additonal debugging information.
260 }
261
262 try {
263 closeSocketToServer();
264 } catch (IOException e) {
265 System.out.println("Couldn't close socket to server."); // Wierd couldn't close the socket to the server
266 e.printStackTrace(); // Output additional debugging information
267 }
268 }
269
270 private void closeSocketToServer() throws IOException {
271 if (serverSocket != null) { // check if the server socket does exist
272 System.out.println("Closing socket to server."); // Say that we are going to close the socket to the server
273 serverSocket.close(); // close the socket to the server
274 }
275 }
276
277 private void closeSocketToClient() throws IOException {
278 System.out.println("Closing socket to client."); // say that we are going to close the socket to the client
279 clientSocket.close(); // close the socket to the client.
280 }
281
282 private void closeStreamToServer() throws IOException {
283 System.out.println("Closing stream to server."); // Say that we are going to close the stream to the server.
284 serverInputStream.close(); // close the stream coming from the server
285 clientOutputStream.flush(); // Send any pending data from the client to the server
286 }
287
288 private void closeStreamFromClient() throws IOException {
289 System.out.println("Closing stream from client."); // sya that we are going to close the stream from the client
290 clientInputStream.close(); // closing the the stream from the client first.
291 serverOutputStream.flush(); // Send any pending data that should go out to the server
292 }
293 }
294