| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.dumprendertree2.forwarder; |
| |
| import android.util.Log; |
| |
| import com.android.dumprendertree2.FsUtils; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.Socket; |
| |
| /** |
| * Worker class for {@link Forwarder}. A ConnectionHandler will be created once the Forwarder |
| * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a |
| * connection already proxied by adb networking (see also {@link AdbUtils}). |
| */ |
| public class ConnectionHandler { |
| |
| private static final String LOG_TAG = "ConnectionHandler"; |
| |
| public static interface OnFinishedCallback { |
| public void onFinished(); |
| } |
| |
| private class SocketPipeThread extends Thread { |
| |
| private InputStream mInputStream; |
| private OutputStream mOutputStream; |
| |
| public SocketPipeThread(InputStream inputStream, OutputStream outputStream) { |
| mInputStream = inputStream; |
| mOutputStream = outputStream; |
| setName("SocketPipeThread: " + getName()); |
| } |
| |
| @Override |
| public void run() { |
| byte[] buffer = new byte[4096]; |
| int length; |
| while (true) { |
| try { |
| if ((length = mInputStream.read(buffer)) < 0) { |
| break; |
| } |
| mOutputStream.write(buffer, 0, length); |
| } catch (IOException e) { |
| /** This exception means one of the streams is closed */ |
| Log.v(LOG_TAG, this.toString(), e); |
| break; |
| } |
| } |
| |
| synchronized (mThreadsRunning) { |
| mThreadsRunning--; |
| if (mThreadsRunning == 0) { |
| ConnectionHandler.this.stop(); |
| mOnFinishedCallback.onFinished(); |
| } |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return getName(); |
| } |
| } |
| |
| private Integer mThreadsRunning; |
| |
| private Socket mFromSocket, mToSocket; |
| private SocketPipeThread mFromToPipe, mToFromPipe; |
| private InputStream mFromSocketInputStream, mToSocketInputStream; |
| private OutputStream mFromSocketOutputStream, mToSocketOutputStream; |
| |
| private int mPort; |
| private String mRemoteMachineIpAddress; |
| |
| private OnFinishedCallback mOnFinishedCallback; |
| |
| public ConnectionHandler(String remoteMachineIp, int port, Socket fromSocket, Socket toSocket) |
| throws IOException { |
| mRemoteMachineIpAddress = remoteMachineIp; |
| mPort = port; |
| |
| mFromSocket = fromSocket; |
| mToSocket = toSocket; |
| |
| try { |
| mFromSocketInputStream = mFromSocket.getInputStream(); |
| mToSocketInputStream = mToSocket.getInputStream(); |
| mFromSocketOutputStream = mFromSocket.getOutputStream(); |
| mToSocketOutputStream = mToSocket.getOutputStream(); |
| AdbUtils.configureConnection(mToSocketInputStream, mToSocketOutputStream, |
| mRemoteMachineIpAddress, mPort); |
| } catch (IOException e) { |
| Log.e(LOG_TAG, "Unable to start ConnectionHandler", e); |
| closeStreams(); |
| throw e; |
| } |
| |
| mFromToPipe = new SocketPipeThread(mFromSocketInputStream, mToSocketOutputStream); |
| mToFromPipe = new SocketPipeThread(mToSocketInputStream, mFromSocketOutputStream); |
| } |
| |
| public void registerOnConnectionHandlerFinishedCallback(OnFinishedCallback callback) { |
| mOnFinishedCallback = callback; |
| } |
| |
| private void closeStreams() { |
| FsUtils.closeInputStream(mFromSocketInputStream); |
| FsUtils.closeInputStream(mToSocketInputStream); |
| FsUtils.closeOutputStream(mFromSocketOutputStream); |
| FsUtils.closeOutputStream(mToSocketOutputStream); |
| } |
| |
| public void start() { |
| /** We have 2 threads running, one for each pipe, that we start here. */ |
| mThreadsRunning = 2; |
| mFromToPipe.start(); |
| mToFromPipe.start(); |
| } |
| |
| public void stop() { |
| shutdown(mFromSocket); |
| shutdown(mToSocket); |
| } |
| |
| private void shutdown(Socket socket) { |
| synchronized (mFromToPipe) { |
| synchronized (mToFromPipe) { |
| /** This will stop the while loop in the run method */ |
| try { |
| if (!socket.isInputShutdown()) { |
| socket.shutdownInput(); |
| } |
| } catch (IOException e) { |
| Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e); |
| } |
| try { |
| if (!socket.isOutputShutdown()) { |
| socket.shutdownOutput(); |
| } |
| } catch (IOException e) { |
| Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e); |
| } |
| try { |
| if (!socket.isClosed()) { |
| socket.close(); |
| } |
| } catch (IOException e) { |
| Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e); |
| } |
| } |
| } |
| } |
| } |