16bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu/*
26bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu * Copyright (C) 2009 The Android Open Source Project
36bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu *
46bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License");
56bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu * you may not use this file except in compliance with the License.
66bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu * You may obtain a copy of the License at
76bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu *
86bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu *      http://www.apache.org/licenses/LICENSE-2.0
96bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu *
106bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu * Unless required by applicable law or agreed to in writing, software
116bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS,
126bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu * See the License for the specific language governing permissions and
146bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu * limitations under the License.
156bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu */
166bf18bae60ae1ff0bf2407e8db115cbbab6f1b84Guang Zhu
17f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhupackage com.android.dumprendertree.forwarder;
18f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
19f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhuimport android.util.Log;
20f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
21f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhuimport java.io.IOException;
22f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhuimport java.io.InputStream;
23f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhuimport java.io.OutputStream;
24f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhuimport java.net.Socket;
25f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
26f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu/**
27f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu *
28f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu * Worker class for {@link ForwardServer}. A Forwarder will be created once the ForwardServer
29f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
30f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu * connection already proxied by adb networking (see also {@link AdbUtils}).
31f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu *
32f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu */
33f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhupublic class Forwarder {
34f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
35f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    private ForwardServer server;
36f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    private Socket from, to;
37f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
38f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    private static final String LOGTAG = "Forwarder";
39f6d1b3f125b06fcc4847be3cfb35e8ce21905676Guang Zhu    private static final int BUFFER_SIZE = 16384;
40f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
41f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    public Forwarder (Socket from, Socket to, ForwardServer server) {
42f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        this.server = server;
43f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        this.from = from;
44f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        this.to = to;
45f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        server.register(this);
46f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
47f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
48f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    public void start() {
49f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        Thread outgoing = new Thread(new SocketPipe(from, to));
50f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        Thread incoming = new Thread(new SocketPipe(to, from));
51f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        outgoing.setName(LOGTAG);
52f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        incoming.setName(LOGTAG);
53f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        outgoing.start();
54f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        incoming.start();
55f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
56f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
57f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    public void stop() {
58f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        shutdown(from);
59f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        shutdown(to);
60f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
61f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
62f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    private void shutdown(Socket socket) {
63f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        try {
64f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            socket.shutdownInput();
65f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        } catch (IOException e) {
66f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            Log.v(LOGTAG, "Socket#shutdownInput", e);
67f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
68f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        try {
69f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            socket.shutdownOutput();
70f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        } catch (IOException e) {
71f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            Log.v(LOGTAG, "Socket#shutdownOutput", e);
72f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
73f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        try {
74f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            socket.close();
75f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        } catch (IOException e) {
76f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            Log.v(LOGTAG, "Socket#close", e);
77f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
78f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
79f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
80f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    private class SocketPipe implements Runnable {
81f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
82f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        private Socket in, out;
83f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
84f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        public SocketPipe(Socket in, Socket out) {
85f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            this.in = in;
86f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            this.out = out;
87f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
88f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
89f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        public void run() {
90f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            try {
91f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                int length;
92f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                InputStream is = in.getInputStream();
93f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                OutputStream os = out.getOutputStream();
94f6d1b3f125b06fcc4847be3cfb35e8ce21905676Guang Zhu                byte[] buffer = new byte[BUFFER_SIZE];
95f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                while ((length = is.read(buffer)) > 0) {
96f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                    os.write(buffer, 0, length);
97f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                }
98f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            } catch (IOException ioe) {
99f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            } finally {
100f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                server.unregister(Forwarder.this);
101f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            }
102f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
103f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
104f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        @Override
105f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        public String toString() {
106f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            return "SocketPipe{" + in + "=>" + out  + "}";
107f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
108f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
109f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu}
110