blob: f19cd41fde410b3e5fe5c64608b5301ad3f95c6d [file] [log] [blame]
/*
* 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);
}
}
}
}
}