156d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski/*
256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * Copyright (C) 2010 The Android Open Source Project
356d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski *
456d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * Licensed under the Apache License, Version 2.0 (the "License");
556d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * you may not use this file except in compliance with the License.
656d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * You may obtain a copy of the License at
756d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski *
856d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski *      http://www.apache.org/licenses/LICENSE-2.0
956d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski *
1056d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * Unless required by applicable law or agreed to in writing, software
1156d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * distributed under the License is distributed on an "AS IS" BASIS,
1256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1356d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * See the License for the specific language governing permissions and
1456d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * limitations under the License.
1556d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski */
1656d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
1756d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowskipackage com.android.dumprendertree2.forwarder;
1856d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
1956d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowskiimport android.util.Log;
2056d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
215af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowskiimport com.android.dumprendertree2.FsUtils;
225af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski
2356d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowskiimport java.io.IOException;
2456d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowskiimport java.io.InputStream;
2556d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowskiimport java.io.OutputStream;
2656d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowskiimport java.net.Socket;
2756d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
2856d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski/**
2956d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * Worker class for {@link Forwarder}. A ConnectionHandler will be created once the Forwarder
3056d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
3156d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski * connection already proxied by adb networking (see also {@link AdbUtils}).
3256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski */
3356d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowskipublic class ConnectionHandler {
3456d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
3556d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    private static final String LOG_TAG = "ConnectionHandler";
3656d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
375926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski    public static interface OnFinishedCallback {
385926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski        public void onFinished();
395926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski    }
405926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski
4156d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    private class SocketPipeThread extends Thread {
4256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
435af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        private InputStream mInputStream;
445af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        private OutputStream mOutputStream;
4556d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
465af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        public SocketPipeThread(InputStream inputStream, OutputStream outputStream) {
475af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            mInputStream = inputStream;
485af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            mOutputStream = outputStream;
495af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            setName("SocketPipeThread: " + getName());
5056d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        }
5156d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
5256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        @Override
5356d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        public void run() {
5456d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski            byte[] buffer = new byte[4096];
5556d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski            int length;
5656d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski            while (true) {
5756d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski                try {
585af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski                    if ((length = mInputStream.read(buffer)) < 0) {
59ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                        break;
6056d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski                    }
615af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski                    mOutputStream.write(buffer, 0, length);
6256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski                } catch (IOException e) {
6356d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski                    /** This exception means one of the streams is closed */
6456d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski                    Log.v(LOG_TAG, this.toString(), e);
6556d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski                    break;
6656d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski                }
6756d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski            }
685926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski
69bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski            synchronized (mThreadsRunning) {
70bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski                mThreadsRunning--;
71bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski                if (mThreadsRunning == 0) {
72bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski                    ConnectionHandler.this.stop();
73bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski                    mOnFinishedCallback.onFinished();
74bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski                }
75bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski            }
7656d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        }
7756d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
7856d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        @Override
7956d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        public String toString() {
805af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            return getName();
8156d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        }
8256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    }
8356d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
84bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski    private Integer mThreadsRunning;
85bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski
8656d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    private Socket mFromSocket, mToSocket;
8756d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    private SocketPipeThread mFromToPipe, mToFromPipe;
885af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski    private InputStream mFromSocketInputStream, mToSocketInputStream;
895af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski    private OutputStream mFromSocketOutputStream, mToSocketOutputStream;
905af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski
915af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski    private int mPort;
925af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski    private String mRemoteMachineIpAddress;
9356d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
945926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski    private OnFinishedCallback mOnFinishedCallback;
955926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski
96898bfbd865496855c3a6c792f9e0da011ae34854Steve Block    public ConnectionHandler(String remoteMachineIp, int port, Socket fromSocket, Socket toSocket)
97898bfbd865496855c3a6c792f9e0da011ae34854Steve Block            throws IOException {
985af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        mRemoteMachineIpAddress = remoteMachineIp;
995af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        mPort = port;
1005af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski
10156d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        mFromSocket = fromSocket;
10256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        mToSocket = toSocket;
1035af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski
1045af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        try {
1055af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            mFromSocketInputStream = mFromSocket.getInputStream();
1065af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            mToSocketInputStream = mToSocket.getInputStream();
1075af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            mFromSocketOutputStream = mFromSocket.getOutputStream();
1085af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            mToSocketOutputStream = mToSocket.getOutputStream();
109898bfbd865496855c3a6c792f9e0da011ae34854Steve Block            AdbUtils.configureConnection(mToSocketInputStream, mToSocketOutputStream,
110898bfbd865496855c3a6c792f9e0da011ae34854Steve Block                    mRemoteMachineIpAddress, mPort);
1115af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        } catch (IOException e) {
1125af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            Log.e(LOG_TAG, "Unable to start ConnectionHandler", e);
1135af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski            closeStreams();
114898bfbd865496855c3a6c792f9e0da011ae34854Steve Block            throw e;
1155af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        }
1165af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski
1175af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        mFromToPipe = new SocketPipeThread(mFromSocketInputStream, mToSocketOutputStream);
1185af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        mToFromPipe = new SocketPipeThread(mToSocketInputStream, mFromSocketOutputStream);
11956d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    }
12056d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
1215926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski    public void registerOnConnectionHandlerFinishedCallback(OnFinishedCallback callback) {
1225926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski        mOnFinishedCallback = callback;
1235926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski    }
1245926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski
1255af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski    private void closeStreams() {
1265af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        FsUtils.closeInputStream(mFromSocketInputStream);
1275af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        FsUtils.closeInputStream(mToSocketInputStream);
1285af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        FsUtils.closeOutputStream(mFromSocketOutputStream);
1295af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski        FsUtils.closeOutputStream(mToSocketOutputStream);
1305af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski    }
1315af84db492a0c198377ba4dacc83c5a211e96ff6Maksymilian Osowski
13256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    public void start() {
133bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski        /** We have 2 threads running, one for each pipe, that we start here. */
134bd8c83db8f424a8cfbf94cd4915d7b99b034358cMaksymilian Osowski        mThreadsRunning = 2;
13556d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        mFromToPipe.start();
13656d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        mToFromPipe.start();
13756d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    }
13856d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
13956d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    public void stop() {
14056d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        shutdown(mFromSocket);
14156d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        shutdown(mToSocket);
14256d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    }
14356d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski
14456d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    private void shutdown(Socket socket) {
145ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski        synchronized (mFromToPipe) {
146ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski            synchronized (mToFromPipe) {
147ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                /** This will stop the while loop in the run method */
148ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                try {
1495926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski                    if (!socket.isInputShutdown()) {
1505926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski                        socket.shutdownInput();
1515926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski                    }
152ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                } catch (IOException e) {
153ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                    Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
154ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                }
155ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                try {
1565926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski                    if (!socket.isOutputShutdown()) {
1575926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski                        socket.shutdownOutput();
1585926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski                    }
159ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                } catch (IOException e) {
160ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                    Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
161ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                }
162ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                try {
1635926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski                    if (!socket.isClosed()) {
1645926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski                        socket.close();
1655926723f82fbdd9b523193e05f901784904b6d38Maksymilian Osowski                    }
166ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                } catch (IOException e) {
167ef9a2175ee29b9a9c84ddd0a02d1ec80ab095222Maksymilian Osowski                    Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
16856d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski                }
16956d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski            }
17056d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski        }
17156d7e400ece64591685c8a21dbb82a94a7bd8010Maksymilian Osowski    }
172898bfbd865496855c3a6c792f9e0da011ae34854Steve Block}
173