1da205a749fadb3a87357d9bd607f094c7717764aJason Monk/** 2da205a749fadb3a87357d9bd607f094c7717764aJason Monk * Copyright (c) 2013, The Android Open Source Project 3da205a749fadb3a87357d9bd607f094c7717764aJason Monk * 4da205a749fadb3a87357d9bd607f094c7717764aJason Monk * Licensed under the Apache License, Version 2.0 (the "License"); 5da205a749fadb3a87357d9bd607f094c7717764aJason Monk * you may not use this file except in compliance with the License. 6da205a749fadb3a87357d9bd607f094c7717764aJason Monk * You may obtain a copy of the License at 7da205a749fadb3a87357d9bd607f094c7717764aJason Monk * 8da205a749fadb3a87357d9bd607f094c7717764aJason Monk * http://www.apache.org/licenses/LICENSE-2.0 9da205a749fadb3a87357d9bd607f094c7717764aJason Monk * 10da205a749fadb3a87357d9bd607f094c7717764aJason Monk * Unless required by applicable law or agreed to in writing, software 11da205a749fadb3a87357d9bd607f094c7717764aJason Monk * distributed under the License is distributed on an "AS IS" BASIS, 12da205a749fadb3a87357d9bd607f094c7717764aJason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13da205a749fadb3a87357d9bd607f094c7717764aJason Monk * See the License for the specific language governing permissions and 14da205a749fadb3a87357d9bd607f094c7717764aJason Monk * limitations under the License. 15da205a749fadb3a87357d9bd607f094c7717764aJason Monk */ 16602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkpackage com.android.proxyhandler; 17602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 186f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monkimport android.net.ProxyProperties; 196f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monkimport android.os.RemoteException; 20602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.util.Log; 21602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 226f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monkimport com.android.net.IProxyPortListener; 23602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport com.google.android.collect.Lists; 24602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 25602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.io.IOException; 26602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.io.InputStream; 27602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.io.OutputStream; 28fa4518f7632f0a2146a0638cf39d6d9e1d832a01Jason Monkimport java.net.InetAddress; 29602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.InetSocketAddress; 30602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.Proxy; 31602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.ProxySelector; 32602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.ServerSocket; 33602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.Socket; 34602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.SocketException; 35602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.URI; 36602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.URISyntaxException; 37602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.util.List; 38602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.util.concurrent.ExecutorService; 39602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.util.concurrent.Executors; 40602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 41602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk/** 42602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk * @hide 43602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk */ 44602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkpublic class ProxyServer extends Thread { 45602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 46602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private static final String CONNECT = "CONNECT"; 47602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private static final String HTTP_OK = "HTTP/1.1 200 OK\n"; 48602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 49602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private static final String TAG = "ProxyServer"; 50602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 51602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private ExecutorService threadExecutor; 52602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 53602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public boolean mIsRunning = false; 54602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 55602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private ServerSocket serverSocket; 566f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk private int mPort; 576f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk private IProxyPortListener mCallback; 58602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 59602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private class ProxyConnection implements Runnable { 60602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private Socket connection; 61602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 62602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private ProxyConnection(Socket connection) { 63602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk this.connection = connection; 64602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 65602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 66602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk @Override 67602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public void run() { 68602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 69602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String requestLine = getLine(connection.getInputStream()); 70602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (requestLine == null) { 71602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk connection.close(); 72602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return; 73602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 74602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String[] splitLine = requestLine.split(" "); 75602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (splitLine.length < 3) { 76602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk connection.close(); 77602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return; 78602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 79602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String requestType = splitLine[0]; 80602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String urlString = splitLine[1]; 81602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 82602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String host = ""; 83602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk int port = 80; 84602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 85602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (requestType.equals(CONNECT)) { 86602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String[] hostPortSplit = urlString.split(":"); 87602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk host = hostPortSplit[0]; 88602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 89602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk port = Integer.parseInt(hostPortSplit[1]); 90602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (NumberFormatException nfe) { 91602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk port = 443; 92602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 93602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk urlString = "Https://" + host + ":" + port; 94602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } else { 95602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 96602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk URI url = new URI(urlString); 97602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk host = url.getHost(); 98602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk port = url.getPort(); 99602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (port < 0) { 100602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk port = 80; 101602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 102602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (URISyntaxException e) { 103602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk connection.close(); 104602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return; 105602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 106602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 107602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 108602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk List<Proxy> list = Lists.newArrayList(); 109602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 110602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk list = ProxySelector.getDefault().select(new URI(urlString)); 111602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (URISyntaxException e) { 112602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk e.printStackTrace(); 113602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 114602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk Socket server = null; 115602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk for (Proxy proxy : list) { 116602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 117602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (!proxy.equals(Proxy.NO_PROXY)) { 118602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk // Only Inets created by PacProxySelector. 119602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk InetSocketAddress inetSocketAddress = 120602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk (InetSocketAddress)list.get(0).address(); 121602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk server = new Socket(inetSocketAddress.getAddress(), 122602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk inetSocketAddress.getPort()); 123602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk sendLine(server, requestLine); 124602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } else { 125602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk server = new Socket(host, port); 126602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (requestType.equals(CONNECT)) { 127602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk while (getLine(connection.getInputStream()).length() != 0); 128602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk // No proxy to respond so we must. 129602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk sendLine(connection, HTTP_OK); 130602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } else { 131602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk sendLine(server, requestLine); 132602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 133602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 134602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (IOException ioe) { 135602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 136602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 137602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (server != null) { 138602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk break; 139602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 140602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 141602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (server == null) { 142602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk server = new Socket(host, port); 143602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (requestType.equals(CONNECT)) { 144602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk while (getLine(connection.getInputStream()).length() != 0); 145602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk // No proxy to respond so we must. 146602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk sendLine(connection, HTTP_OK); 147602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } else { 148602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk sendLine(server, requestLine); 149602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 150602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 151602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk // Pass data back and forth until complete. 152602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk SocketConnect.connect(connection, server); 153602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (IOException e) { 154602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk Log.d(TAG, "Problem Proxying", e); 155602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 156602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 157602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk connection.close(); 158602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (IOException ioe) { 159602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 160602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 161602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 162602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 163602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private String getLine(InputStream inputStream) throws IOException { 164602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk StringBuffer buffer = new StringBuffer(); 165602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk int byteBuffer = inputStream.read(); 166602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (byteBuffer < 0) return ""; 167602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk do { 168602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (byteBuffer != '\r') { 169602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk buffer.append((char)byteBuffer); 170602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 171602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk byteBuffer = inputStream.read(); 172602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } while ((byteBuffer != '\n') && (byteBuffer >= 0)); 173602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 174602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return buffer.toString(); 175602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 176602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 177602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private void sendLine(Socket socket, String line) throws IOException { 178602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk OutputStream os = socket.getOutputStream(); 179602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk os.write(line.getBytes()); 180602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk os.write('\r'); 181602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk os.write('\n'); 182602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk os.flush(); 183602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 184602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 185602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 186602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public ProxyServer() { 187602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk threadExecutor = Executors.newCachedThreadPool(); 1886f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk mPort = -1; 1896f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk mCallback = null; 190602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 191602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 192602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk @Override 193602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public void run() { 194602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 1956f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk serverSocket = new ServerSocket(0); 196602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 1976f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk if (serverSocket != null) { 1986f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk setPort(serverSocket.getLocalPort()); 199602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 2006f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk while (mIsRunning) { 2016f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk try { 202fa4518f7632f0a2146a0638cf39d6d9e1d832a01Jason Monk Socket socket = serverSocket.accept(); 203fa4518f7632f0a2146a0638cf39d6d9e1d832a01Jason Monk // Only receive local connections. 204fa4518f7632f0a2146a0638cf39d6d9e1d832a01Jason Monk if (socket.getInetAddress().isLoopbackAddress()) { 205fa4518f7632f0a2146a0638cf39d6d9e1d832a01Jason Monk ProxyConnection parser = new ProxyConnection(socket); 206602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 207fa4518f7632f0a2146a0638cf39d6d9e1d832a01Jason Monk threadExecutor.execute(parser); 208fa4518f7632f0a2146a0638cf39d6d9e1d832a01Jason Monk } else { 209fa4518f7632f0a2146a0638cf39d6d9e1d832a01Jason Monk socket.close(); 210fa4518f7632f0a2146a0638cf39d6d9e1d832a01Jason Monk } 2116f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } catch (IOException e) { 2126f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk e.printStackTrace(); 2136f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 214602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 215602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 216602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (SocketException e) { 2176f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk Log.e(TAG, "Failed to start proxy server", e); 2186f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } catch (IOException e1) { 2196f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk Log.e(TAG, "Failed to start proxy server", e1); 220602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 221602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 222602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mIsRunning = false; 223602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 224602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 2256f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk public synchronized void setPort(int port) { 2266f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk if (mCallback != null) { 2276f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk try { 2286f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk mCallback.setProxyPort(port); 2296f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } catch (RemoteException e) { 2306f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk Log.w(TAG, "Proxy failed to report port to PacManager", e); 2316f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 2326f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 2336f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk mPort = port; 2346f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 2356f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk 2366f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk public synchronized void setCallback(IProxyPortListener callback) { 2376f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk if (mPort != -1) { 2386f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk try { 2396f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk callback.setProxyPort(mPort); 2406f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } catch (RemoteException e) { 2416f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk Log.w(TAG, "Proxy failed to report port to PacManager", e); 2426f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 2436f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 2446f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk mCallback = callback; 2456f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 2466f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk 247602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public synchronized void startServer() { 248602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mIsRunning = true; 249602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk start(); 250602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 251602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 252602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public synchronized void stopServer() { 253602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mIsRunning = false; 254602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (serverSocket != null) { 255602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 256602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk serverSocket.close(); 257602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk serverSocket = null; 258602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (IOException e) { 259602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk e.printStackTrace(); 260602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 261602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 262602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 2636f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk 2646f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk public boolean isBound() { 2656f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk return (mPort != -1); 2666f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 2676f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk 2686f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk public int getPort() { 2696f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk return mPort; 2706f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 271602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk} 272