ConnectionHandler.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.io.InputStream;
23import java.io.OutputStream;
24import java.net.Socket;
25
26/**
27 * Worker class for {@link Forwarder}. A ConnectionHandler will be created once the Forwarder
28 * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
29 * connection already proxied by adb networking (see also {@link AdbUtils}).
30 */
31public class ConnectionHandler {
32
33    private static final String LOG_TAG = "ConnectionHandler";
34
35    public static interface OnFinishedCallback {
36        public void onFinished();
37    }
38
39    private class SocketPipeThread extends Thread {
40
41        private Socket mInSocket, mOutSocket;
42
43        public SocketPipeThread(Socket inSocket, Socket outSocket) {
44            mInSocket = inSocket;
45            mOutSocket = outSocket;
46        }
47
48        @Override
49        public void run() {
50            InputStream is;
51            OutputStream os;
52            try {
53                synchronized (this) {
54                    is = mInSocket.getInputStream();
55                    os = mOutSocket.getOutputStream();
56                }
57            } catch (IOException e) {
58                Log.w(LOG_TAG, this.toString(), e);
59                finish();
60                return;
61            }
62
63            byte[] buffer = new byte[4096];
64            int length;
65            while (true) {
66                try {
67                    if ((length = is.read(buffer)) <= 0) {
68                        break;
69                    }
70                    os.write(buffer, 0, length);
71                } catch (IOException e) {
72                    /** This exception means one of the streams is closed */
73                    Log.v(LOG_TAG, this.toString(), e);
74                    break;
75                }
76            }
77
78            finish();
79        }
80
81        private void finish() {
82            synchronized (mThreadsRunning) {
83                mThreadsRunning--;
84                if (mThreadsRunning == 0) {
85                    ConnectionHandler.this.stop();
86                    mOnFinishedCallback.onFinished();
87                }
88            }
89        }
90
91        @Override
92        public String toString() {
93            return "SocketPipeThread:\n" + mInSocket + "\n=>\n" + mOutSocket;
94        }
95    }
96
97    private Integer mThreadsRunning;
98
99    private Socket mFromSocket, mToSocket;
100    private SocketPipeThread mFromToPipe, mToFromPipe;
101
102    private OnFinishedCallback mOnFinishedCallback;
103
104    public ConnectionHandler(Socket fromSocket, Socket toSocket) {
105        mFromSocket = fromSocket;
106        mToSocket = toSocket;
107        mFromToPipe = new SocketPipeThread(mFromSocket, mToSocket);
108        mToFromPipe = new SocketPipeThread(mToSocket, mFromSocket);
109    }
110
111    public void registerOnConnectionHandlerFinishedCallback(OnFinishedCallback callback) {
112        mOnFinishedCallback = callback;
113    }
114
115    public void start() {
116        /** We have 2 threads running, one for each pipe, that we start here. */
117        mThreadsRunning = 2;
118        mFromToPipe.start();
119        mToFromPipe.start();
120    }
121
122    public void stop() {
123        shutdown(mFromSocket);
124        shutdown(mToSocket);
125    }
126
127    private void shutdown(Socket socket) {
128        synchronized (mFromToPipe) {
129            synchronized (mToFromPipe) {
130                /** This will stop the while loop in the run method */
131                try {
132                    if (!socket.isInputShutdown()) {
133                        socket.shutdownInput();
134                    }
135                } catch (IOException e) {
136                    Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
137                }
138                try {
139                    if (!socket.isOutputShutdown()) {
140                        socket.shutdownOutput();
141                    }
142                } catch (IOException e) {
143                    Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
144                }
145                try {
146                    if (!socket.isClosed()) {
147                        socket.close();
148                    }
149                } catch (IOException e) {
150                    Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
151                }
152            }
153        }
154    }
155}