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";
39f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
40f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    public Forwarder (Socket from, Socket to, ForwardServer server) {
41f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        this.server = server;
42f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        this.from = from;
43f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        this.to = to;
44f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        server.register(this);
45f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
46f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
47f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    public void start() {
48f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        Thread outgoing = new Thread(new SocketPipe(from, to));
49f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        Thread incoming = new Thread(new SocketPipe(to, from));
50f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        outgoing.setName(LOGTAG);
51f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        incoming.setName(LOGTAG);
52f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        outgoing.start();
53f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        incoming.start();
54f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
55f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
56f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    public void stop() {
57f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        shutdown(from);
58f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        shutdown(to);
59f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
60f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
61f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    private void shutdown(Socket socket) {
62f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        try {
63f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            socket.shutdownInput();
64f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        } catch (IOException e) {
65f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            Log.v(LOGTAG, "Socket#shutdownInput", e);
66f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
67f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        try {
68f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            socket.shutdownOutput();
69f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        } catch (IOException e) {
70f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            Log.v(LOGTAG, "Socket#shutdownOutput", e);
71f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
72f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        try {
73f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            socket.close();
74f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        } catch (IOException e) {
75f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            Log.v(LOGTAG, "Socket#close", e);
76f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
77f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
78f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
79f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    private class SocketPipe implements Runnable {
80f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
81f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        private Socket in, out;
82f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
83f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        public SocketPipe(Socket in, Socket out) {
84f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            this.in = in;
85f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            this.out = out;
86f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
87f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
88f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        public void run() {
89f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            try {
90f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                int length;
91f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                InputStream is = in.getInputStream();
92f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                OutputStream os = out.getOutputStream();
93f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                byte[] buffer = new byte[4096];
94f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                while ((length = is.read(buffer)) > 0) {
95f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                    os.write(buffer, 0, length);
96f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                }
97f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            } catch (IOException ioe) {
98f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            } finally {
99f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu                server.unregister(Forwarder.this);
100f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            }
101f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
102f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu
103f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        @Override
104f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        public String toString() {
105f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu            return "SocketPipe{" + in + "=>" + out  + "}";
106f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu        }
107f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu    }
108f4bf552b5a5046e7648f405115ee48917b15b9aaGuang Zhu}
109