Forwarder.java revision bd8c83db8f424a8cfbf94cd4915d7b99b034358c
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dumprendertree2.forwarder; 18 19import android.util.Log; 20 21import java.io.IOException; 22import java.net.ServerSocket; 23import java.net.Socket; 24import java.util.HashSet; 25import java.util.Set; 26 27/** 28 * A port forwarding server. Listens on localhost on specified port and forwards the tcp 29 * communications to external socket via adb networking proxy. 30 */ 31public class Forwarder extends Thread { 32 private static final String LOG_TAG = "Forwarder"; 33 34 private int mPort; 35 private String mRemoteMachineIpAddress; 36 37 private ServerSocket mServerSocket; 38 39 private Set<ConnectionHandler> mConnectionHandlers = new HashSet<ConnectionHandler>(); 40 41 public Forwarder(int port, String remoteMachineIpAddress) { 42 mPort = port; 43 mRemoteMachineIpAddress = remoteMachineIpAddress; 44 } 45 46 @Override 47 public void start() { 48 Log.i(LOG_TAG, "start(): Starting fowarder on port: " + mPort); 49 50 try { 51 mServerSocket = new ServerSocket(mPort); 52 } catch (IOException e) { 53 Log.e(LOG_TAG, "mPort=" + mPort, e); 54 return; 55 } 56 57 super.start(); 58 } 59 60 @Override 61 public void run() { 62 while (true) { 63 /** These sockets will be closed when Forwarder.stop() is called */ 64 Socket localSocket; 65 Socket remoteSocket; 66 try { 67 localSocket = mServerSocket.accept(); 68 remoteSocket = AdbUtils.getSocketToRemoteMachine(mRemoteMachineIpAddress, 69 mPort); 70 } catch (IOException e) { 71 /** This most likely means that mServerSocket is already closed */ 72 Log.w(LOG_TAG, "mPort=" + mPort, e); 73 break; 74 } 75 76 if (remoteSocket == null) { 77 try { 78 localSocket.close(); 79 } catch (IOException e) { 80 Log.e(LOG_TAG, "mPort=" + mPort, e); 81 } 82 83 Log.e(LOG_TAG, "run(): mPort= " + mPort + " Failed to start forwarding from " + 84 localSocket); 85 continue; 86 } 87 88 final ConnectionHandler connectionHandler = 89 new ConnectionHandler(localSocket, remoteSocket); 90 91 /** 92 * We have to close the sockets after the ConnectionHandler finishes, so we 93 * don't get "Too may open files" exception. We also remove the ConnectionHandler 94 * from the collection to avoid memory issues. 95 * */ 96 ConnectionHandler.OnFinishedCallback callback = 97 new ConnectionHandler.OnFinishedCallback() { 98 @Override 99 public void onFinished() { 100 synchronized (this) { 101 if (mConnectionHandlers.remove(connectionHandler)) { 102 Log.d(LOG_TAG, "removeConnectionHandler(): removed"); 103 } else { 104 assert false : "removeConnectionHandler(): not in the collection"; 105 } 106 } 107 } 108 }; 109 connectionHandler.registerOnConnectionHandlerFinishedCallback(callback); 110 111 synchronized (this) { 112 mConnectionHandlers.add(connectionHandler); 113 } 114 connectionHandler.start(); 115 } 116 117 synchronized (this) { 118 for (ConnectionHandler connectionHandler : mConnectionHandlers) { 119 connectionHandler.stop(); 120 } 121 } 122 } 123 124 public void finish() { 125 try { 126 mServerSocket.close(); 127 } catch (IOException e) { 128 Log.e(LOG_TAG, "mPort=" + mPort, e); 129 } 130 } 131}