001: /*
002: * Copyright 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.util;
017:
018: import java.io.InputStream;
019: import java.io.OutputStream;
020: import java.io.UnsupportedEncodingException;
021: import java.net.ServerSocket;
022: import java.net.Socket;
023:
024: /**
025: * A blind byte-by-byte bi-directional proxy.
026: */
027: public class NetProxy {
028:
029: private class ClientToServerProxyConnection extends ProxyConnection {
030: public ClientToServerProxyConnection(Socket clientSideSocket,
031: Socket serverSideSocket) {
032: super (clientSideSocket, serverSideSocket);
033: setName(fromPort + " => " + toPort + " #" + connections);
034: }
035:
036: protected void recordBytesTransferred(byte[] bytes, int avail) {
037: addBytesSent(avail, bytes);
038: }
039: }
040:
041: private abstract class ProxyConnection extends Thread {
042: private Socket fromSocket;
043: private Socket toSocket;
044:
045: public ProxyConnection(Socket fromSocket, Socket toSocket) {
046: this .fromSocket = fromSocket;
047: this .toSocket = toSocket;
048: }
049:
050: public void run() {
051: try {
052: InputStream fromSideInput = fromSocket.getInputStream();
053: OutputStream toSideOutput = toSocket.getOutputStream();
054:
055: /*
056: * Spin and pass data in one direction.
057: */
058: int avail;
059: byte[] bytes = new byte[32768];
060: while (true) {
061: // Read 'from' side
062: avail = fromSideInput.read(bytes);
063: if (avail > 0) {
064: // Forward to 'to' side
065: toSideOutput.write(bytes, 0, avail);
066: // Accumulate bytes received
067: recordBytesTransferred(bytes, avail);
068: } else if (avail == -1) {
069: break;
070: }
071: }
072: } catch (Throwable e) {
073: } finally {
074: try {
075: fromSocket.close();
076: toSocket.close();
077: } catch (Throwable e) {
078: }
079: }
080: }
081:
082: protected abstract void recordBytesTransferred(byte[] bytes,
083: int avail);
084: }
085:
086: private class ServerToClientProxyConnection extends ProxyConnection {
087: public ServerToClientProxyConnection(Socket clientSideSocket,
088: Socket serverSideSocket) {
089: super (serverSideSocket, clientSideSocket);
090: setName(fromPort + " <= " + toPort + " #" + connections);
091: }
092:
093: protected void recordBytesTransferred(byte[] bytes, int avail) {
094: addBytesReceived(avail, bytes);
095: }
096: }
097:
098: public static void main(String[] args) {
099: if (args.length < 2) {
100: System.out
101: .println("Usage: NetProxy <local-port> <remote-port> [<remote-host>]");
102: return;
103: }
104:
105: int localPort = Integer.parseInt(args[0]);
106: int remotePort = Integer.parseInt(args[1]);
107: String remoteHost = args.length < 3 ? "localhost" : args[2];
108: NetProxy netProxy = new NetProxy(localPort, remoteHost,
109: remotePort, true);
110: netProxy.run();
111: }
112:
113: private boolean dumpChars;
114: private int fromPort;
115: private String toName;
116: private int toPort;
117: private int bytesSent;
118: private int bytesReceived;
119:
120: private int connections;
121:
122: private boolean end;
123:
124: private long startTime = System.currentTimeMillis();
125:
126: public NetProxy(int fromPort, String toName, int toPort,
127: boolean dumpChars) {
128: this .fromPort = fromPort;
129: this .toName = toName;
130: this .toPort = toPort;
131: this .dumpChars = dumpChars;
132: }
133:
134: public void end() {
135: end = true;
136: }
137:
138: public void run() {
139: try {
140: System.out
141: .println("Time\tBytes Sent\tBytes Received\tTotal Bytes\tHTTP Data");
142: ServerSocket serverSocket = new ServerSocket(fromPort);
143: while (!end) {
144: try {
145: ++connections;
146:
147: /*
148: * Listen for and accept the client-initiated connection. Connect to
149: * the real server. Spawn a thread to handle the data shuffling for
150: * newly-created connection.
151: */
152: Socket clientSideSocket = serverSocket.accept();
153: clientSideSocket.setTcpNoDelay(true);
154:
155: Socket serverSideSocket = new Socket(toName, toPort);
156: serverSideSocket.setTcpNoDelay(true);
157:
158: new ClientToServerProxyConnection(clientSideSocket,
159: serverSideSocket).start();
160: new ServerToClientProxyConnection(clientSideSocket,
161: serverSideSocket).start();
162: } catch (Throwable e) {
163: e.printStackTrace();
164: }
165: }
166: } catch (Throwable e) {
167: // Failed to even be able to listen.
168: e.printStackTrace();
169: }
170: }
171:
172: protected int getBytesReceived() {
173: return bytesReceived;
174: }
175:
176: protected int getBytesSent() {
177: return bytesSent;
178: }
179:
180: private synchronized void addBytesReceived(int byteCount,
181: byte[] bytes) {
182: bytesReceived += byteCount;
183: log(0, byteCount, bytes);
184: }
185:
186: private synchronized void addBytesSent(int byteCount, byte[] bytes) {
187: this .bytesSent += byteCount;
188: log(byteCount, 0, bytes);
189: }
190:
191: private synchronized void log(int bytesSent, int bytesReceived,
192: byte[] dataBuffer) {
193: System.out.print(System.currentTimeMillis() - startTime);
194: System.out.print("\t");
195: System.out.print(bytesSent);
196: System.out.print("\t");
197: System.out.print(bytesReceived);
198: System.out.print("\t");
199: System.out.print(this .bytesSent + this .bytesReceived);
200: System.out.print("\t");
201: char ch;
202: int avail = (bytesSent != 0 ? bytesSent : bytesReceived);
203: if (dumpChars) {
204: int limit = (avail < 1024 ? avail : 1024);
205: for (int i = 0; i < limit; ++i) {
206: ch = (char) dataBuffer[i];
207: if (ch >= 32 && ch < 128) {
208: System.out.print(ch);
209: } else if (ch == '\n') {
210: System.out.print("\\n");
211: } else if (ch == '\r') {
212: System.out.print("\\r");
213: } else {
214: System.out.print('.');
215: }
216: }
217: } else {
218: // Just read up to the \r\n\r\n.
219: //
220: try {
221: String http = new String(dataBuffer, "UTF-8");
222: int endOfHeaders = http.indexOf("\r\n\r\n");
223: if (endOfHeaders != -1 && http.indexOf("HTTP") != -1) {
224: http = http.replaceAll("\\r", "");
225: http = http.replaceAll("\\n", "\n\t\t\t\t");
226: System.out.print(http.substring(0, endOfHeaders));
227: } else {
228: System.out.print("(data)");
229: }
230: } catch (UnsupportedEncodingException e) {
231: e.printStackTrace();
232: }
233: }
234:
235: System.out.println();
236: }
237: }
|