Java tutorial
/* This file is part of ServerProxy. SocketProxy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Subsonic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Subsonic. If not, see <http://www.gnu.org/licenses/>. Copyright 2014 (C) Scott Jackson */ package github.daneren2005.serverproxy; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.net.URLDecoder; import java.net.URLEncoder; import java.net.UnknownHostException; import java.nio.ByteOrder; import java.util.StringTokenizer; import org.apache.http.Header; import org.apache.http.HttpRequest; import org.apache.http.message.BasicHttpRequest; import android.content.Context; import android.net.wifi.WifiManager; import android.util.Log; public abstract class ServerProxy implements Runnable { private static final String TAG = ServerProxy.class.getSimpleName(); private Thread thread; protected boolean isRunning; private ServerSocket socket; private int port; private Context context; public ServerProxy(Context context) { // Create listening socket try { socket = new ServerSocket(0); socket.setSoTimeout(5000); port = socket.getLocalPort(); this.context = context; } catch (UnknownHostException e) { // impossible } catch (IOException e) { Log.e(TAG, "IOException initializing server", e); } } public void start() { if (socket.isBound()) { thread = new Thread(this, "Socket Proxy"); thread.start(); } else { Log.e(TAG, "Attempting to start a non-initialized proxy"); } } public void stop() { isRunning = false; if (thread != null) { thread.interrupt(); } } public String getPrivateAddress(String request) { return getAddress("127.0.0.1", request); } public String getPublicAddress(String request) { WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); int ipAddress = wifiManager.getConnectionInfo().getIpAddress(); if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) { ipAddress = Integer.reverseBytes(ipAddress); } byte[] ipByteArray = BigInteger.valueOf(ipAddress).toByteArray(); String ipAddressString = null; try { ipAddressString = InetAddress.getByAddress(ipByteArray).getHostAddress(); } catch (UnknownHostException ex) { Log.e(TAG, "Unable to get host address."); } return getAddress(ipAddressString, request); } private String getAddress(String host, String request) { try { return String.format("http://%s:%d/%s", host, port, URLEncoder.encode(request, "UTF-8")); } catch (UnsupportedEncodingException e) { return null; } } @Override public void run() { isRunning = true; while (isRunning) { try { Socket client = socket.accept(); if (client == null) { continue; } Log.i(TAG, "client connected"); ProxyTask task = getTask(client); if (task.processRequest()) { new Thread(task, "ProxyTask").start(); } } catch (SocketTimeoutException e) { // Do nothing } catch (IOException e) { Log.e(TAG, "Error connecting to client", e); } } Log.i(TAG, "Proxy interrupted. Shutting down."); } abstract ProxyTask getTask(Socket client); protected abstract class ProxyTask implements Runnable { protected Socket client; protected String path; protected int cbSkip = 0; protected HttpRequest request; public ProxyTask(Socket client) { this.client = client; } protected HttpRequest readRequest() { HttpRequest request = null; InputStream is; String firstLine; BufferedReader reader = null; try { is = client.getInputStream(); reader = new BufferedReader(new InputStreamReader(is), 8192); firstLine = reader.readLine(); } catch (IOException e) { Log.e(TAG, "Error parsing request", e); return request; } if (firstLine == null) { Log.i(TAG, "Proxy client closed connection without a request."); return request; } StringTokenizer st = new StringTokenizer(firstLine); String method = st.nextToken(); String uri = st.nextToken(); String realUri = uri.substring(1); request = new BasicHttpRequest(method, realUri); // Get all of the headers try { String line; while ((line = reader.readLine()) != null && !"".equals(line)) { String headerName = line.substring(0, line.indexOf(':')); String headerValue = line.substring(line.indexOf(": ") + 2); request.addHeader(headerName, headerValue); } } catch (IOException e) { // Don't really care once past first line } return request; } public boolean processRequest() { request = readRequest(); if (request == null) { return false; } // Read HTTP headers try { path = URLDecoder.decode(request.getRequestLine().getUri(), "UTF-8"); } catch (UnsupportedEncodingException e) { Log.e(TAG, "Unsupported encoding", e); return false; } Log.i(TAG, "Processing request for " + path); // Try to get range requested Header rangeHeader = request.getFirstHeader("Range"); if (rangeHeader != null) { String range = rangeHeader.getValue(); int index = range.indexOf("="); if (index >= 0) { range = range.substring(index + 1); index = range.indexOf("-"); if (index > 0) { range = range.substring(0, index); } cbSkip = Integer.parseInt(range); } } return true; } } }