Loading tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/AdbUtils.java 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * 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 java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /** * The utility class that can setup a socket allowing the device to communicate with remote * machines through the machine that the device is connected to via adb. */ public class AdbUtils { private static final String LOG_TAG = "AdbUtils"; private static final String ADB_OK = "OKAY"; private static final int ADB_PORT = 5037; private static final String ADB_HOST = "127.0.0.1"; private static final int ADB_RESPONSE_SIZE = 4; /** * Send an ADB command using existing socket connection * * The streams provided must be from a socket connected to adb already * * @param is input stream of the socket connection * @param os output stream of the socket * @param cmd the adb command to send * @return if adb gave a success response * @throws IOException */ private static boolean sendAdbCmd(InputStream is, OutputStream os, String cmd) throws IOException { byte[] buf = new byte[ADB_RESPONSE_SIZE]; cmd = String.format("%04X", cmd.length()) + cmd; os.write(cmd.getBytes()); int read = is.read(buf); if (read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) { Log.w(LOG_TAG, "adb cmd faild."); return false; } return true; } /** * Get a tcp socket connection to specified IP address and port proxied by adb * * The proxying is transparent, e.g. if a socket is returned, then it can be written to and * read from as if it is directly connected to the target * * @param remoteAddress IP address of the host to connect to * @param remotePort port of the host to connect to * @return a valid Socket instance if successful, null otherwise */ public static Socket getSocketToRemoteMachine(String remoteAddress, int remotePort) { try { Socket socket = new Socket(ADB_HOST, ADB_PORT); String cmd = "tcp:" + remotePort + ":" + remoteAddress; if (!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) { socket.close(); return null; } return socket; } catch (IOException ioe) { Log.w(LOG_TAG, "error creating adb socket", ioe); return null; } } } No newline at end of file tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ConnectionHandler.java 0 → 100644 +116 −0 Original line number Diff line number Diff line /* * 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 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"; private class SocketPipeThread extends Thread { private Socket mInSocket, mOutSocket; public SocketPipeThread(Socket inSocket, Socket outSocket) { mInSocket = inSocket; mOutSocket = outSocket; } @Override public void run() { InputStream is; OutputStream os; try { synchronized (this) { is = mInSocket.getInputStream(); os = mOutSocket.getOutputStream(); } } catch (IOException e) { Log.w(LOG_TAG, this.toString(), e); return; } byte[] buffer = new byte[4096]; int length; while (true) { try { synchronized (this) { if ((length = is.read(buffer)) <= 0) { break; } os.write(buffer, 0, length); } } catch (IOException e) { /** This exception means one of the streams is closed */ Log.v(LOG_TAG, this.toString(), e); break; } } } @Override public String toString() { return "SocketPipeThread:\n" + mInSocket + "\n=>\n" + mOutSocket; } } private Socket mFromSocket, mToSocket; private SocketPipeThread mFromToPipe, mToFromPipe; public ConnectionHandler(Socket fromSocket, Socket toSocket) { mFromSocket = fromSocket; mToSocket = toSocket; mFromToPipe = new SocketPipeThread(mFromSocket, mToSocket); mToFromPipe = new SocketPipeThread(mToSocket, mFromSocket); } public void start() { mFromToPipe.start(); mToFromPipe.start(); } public void stop() { shutdown(mFromSocket); shutdown(mToSocket); } private void shutdown(Socket socket) { try { synchronized (mFromToPipe) { synchronized (mToFromPipe) { /** This will stop the while loop in the run method */ socket.shutdownInput(); socket.shutdownOutput(); socket.close(); } } } catch (IOException e) { Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e); } } } No newline at end of file tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/Forwarder.java 0 → 100644 +131 −0 Original line number Diff line number Diff line /* * 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 java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.HashSet; import java.util.Set; /** * A port forwarding server. Listens on localhost on specified port and forwards the tcp * communications to external socket via adb networking proxy. */ public class Forwarder extends Thread { private static final String LOG_TAG = "Forwarder"; private int mPort; private String mRemoteMachineIpAddress; private Boolean mIsRunning = false; private ServerSocket mServerSocket; private Set<ConnectionHandler> mConnectionHandlers = new HashSet<ConnectionHandler>(); public Forwarder(int port, String remoteMachineIpAddress) { mPort = port; mRemoteMachineIpAddress = remoteMachineIpAddress; } @Override public void start() { Log.i(LOG_TAG, "start(): Starting fowarder on port: " + mPort); synchronized (this) { if (mIsRunning) { Log.w(LOG_TAG, "start(): Forwarder on port: " + mPort + " already running! NOOP."); return; } } try { mServerSocket = new ServerSocket(mPort); } catch (IOException e) { Log.e(LOG_TAG, "mPort=" + mPort, e); return; } mIsRunning = true; super.start(); } @Override public void run() { while (true) { synchronized (this) { if (!mIsRunning) { return; } /** These sockets will be closed when Forwarder.stop() is called */ Socket localSocket; Socket remoteSocket; try { localSocket = mServerSocket.accept(); remoteSocket = AdbUtils.getSocketToRemoteMachine(mRemoteMachineIpAddress, mPort); } catch (IOException e) { /** This most likely means that mServerSocket is already closed */ Log.w(LOG_TAG + "mPort=" + mPort, e); return; } if (remoteSocket == null) { try { localSocket.close(); } catch (IOException e) { Log.e(LOG_TAG, "mPort=" + mPort, e); } Log.e(LOG_TAG, "run(): mPort= " + mPort + " Failed to start forwarding from " + localSocket); continue; } ConnectionHandler forwarder = new ConnectionHandler(localSocket, remoteSocket); mConnectionHandlers.add(forwarder); forwarder.start(); } } } public void finish() { synchronized (this) { if (!mIsRunning) { return; } } try { mServerSocket.close(); } catch (IOException e) { Log.e(LOG_TAG, "mPort=" + mPort, e); } synchronized (this) { mIsRunning = false; } for (ConnectionHandler connectionHandler : mConnectionHandlers) { connectionHandler.stop(); } mConnectionHandlers.clear(); } } No newline at end of file tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ForwarderManager.java 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * 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 java.util.HashSet; import java.util.Set; /** * A simple class to start and stop Forwarders running on some ports. * * It uses a singleton pattern and is thread safe. */ public class ForwarderManager { /** * The IP address of the server serving the tests. */ private static final String HOST_IP = "127.0.0.1"; /** * We use these ports because other webkit platforms do. They are set up in * external/webkit/LayoutTests/http/conf/apache2-debian-httpd.conf */ public static final int HTTP_PORT = 8080; public static final int HTTPS_PORT = 8443; private static ForwarderManager forwarderManager; private Set<Forwarder> mServers; private ForwarderManager() { mServers = new HashSet<Forwarder>(2); mServers.add(new Forwarder(HTTP_PORT, HOST_IP)); mServers.add(new Forwarder(HTTPS_PORT, HOST_IP)); } public static synchronized ForwarderManager getForwarderManager() { if (forwarderManager == null) { forwarderManager = new ForwarderManager(); } return forwarderManager; } @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } public synchronized void start() { for (Forwarder server : mServers) { server.start(); } } public synchronized void stop() { for (Forwarder server : mServers) { server.finish(); } } } No newline at end of file Loading
tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/AdbUtils.java 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * 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 java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /** * The utility class that can setup a socket allowing the device to communicate with remote * machines through the machine that the device is connected to via adb. */ public class AdbUtils { private static final String LOG_TAG = "AdbUtils"; private static final String ADB_OK = "OKAY"; private static final int ADB_PORT = 5037; private static final String ADB_HOST = "127.0.0.1"; private static final int ADB_RESPONSE_SIZE = 4; /** * Send an ADB command using existing socket connection * * The streams provided must be from a socket connected to adb already * * @param is input stream of the socket connection * @param os output stream of the socket * @param cmd the adb command to send * @return if adb gave a success response * @throws IOException */ private static boolean sendAdbCmd(InputStream is, OutputStream os, String cmd) throws IOException { byte[] buf = new byte[ADB_RESPONSE_SIZE]; cmd = String.format("%04X", cmd.length()) + cmd; os.write(cmd.getBytes()); int read = is.read(buf); if (read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) { Log.w(LOG_TAG, "adb cmd faild."); return false; } return true; } /** * Get a tcp socket connection to specified IP address and port proxied by adb * * The proxying is transparent, e.g. if a socket is returned, then it can be written to and * read from as if it is directly connected to the target * * @param remoteAddress IP address of the host to connect to * @param remotePort port of the host to connect to * @return a valid Socket instance if successful, null otherwise */ public static Socket getSocketToRemoteMachine(String remoteAddress, int remotePort) { try { Socket socket = new Socket(ADB_HOST, ADB_PORT); String cmd = "tcp:" + remotePort + ":" + remoteAddress; if (!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) { socket.close(); return null; } return socket; } catch (IOException ioe) { Log.w(LOG_TAG, "error creating adb socket", ioe); return null; } } } No newline at end of file
tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ConnectionHandler.java 0 → 100644 +116 −0 Original line number Diff line number Diff line /* * 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 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"; private class SocketPipeThread extends Thread { private Socket mInSocket, mOutSocket; public SocketPipeThread(Socket inSocket, Socket outSocket) { mInSocket = inSocket; mOutSocket = outSocket; } @Override public void run() { InputStream is; OutputStream os; try { synchronized (this) { is = mInSocket.getInputStream(); os = mOutSocket.getOutputStream(); } } catch (IOException e) { Log.w(LOG_TAG, this.toString(), e); return; } byte[] buffer = new byte[4096]; int length; while (true) { try { synchronized (this) { if ((length = is.read(buffer)) <= 0) { break; } os.write(buffer, 0, length); } } catch (IOException e) { /** This exception means one of the streams is closed */ Log.v(LOG_TAG, this.toString(), e); break; } } } @Override public String toString() { return "SocketPipeThread:\n" + mInSocket + "\n=>\n" + mOutSocket; } } private Socket mFromSocket, mToSocket; private SocketPipeThread mFromToPipe, mToFromPipe; public ConnectionHandler(Socket fromSocket, Socket toSocket) { mFromSocket = fromSocket; mToSocket = toSocket; mFromToPipe = new SocketPipeThread(mFromSocket, mToSocket); mToFromPipe = new SocketPipeThread(mToSocket, mFromSocket); } public void start() { mFromToPipe.start(); mToFromPipe.start(); } public void stop() { shutdown(mFromSocket); shutdown(mToSocket); } private void shutdown(Socket socket) { try { synchronized (mFromToPipe) { synchronized (mToFromPipe) { /** This will stop the while loop in the run method */ socket.shutdownInput(); socket.shutdownOutput(); socket.close(); } } } catch (IOException e) { Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e); } } } No newline at end of file
tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/Forwarder.java 0 → 100644 +131 −0 Original line number Diff line number Diff line /* * 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 java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.HashSet; import java.util.Set; /** * A port forwarding server. Listens on localhost on specified port and forwards the tcp * communications to external socket via adb networking proxy. */ public class Forwarder extends Thread { private static final String LOG_TAG = "Forwarder"; private int mPort; private String mRemoteMachineIpAddress; private Boolean mIsRunning = false; private ServerSocket mServerSocket; private Set<ConnectionHandler> mConnectionHandlers = new HashSet<ConnectionHandler>(); public Forwarder(int port, String remoteMachineIpAddress) { mPort = port; mRemoteMachineIpAddress = remoteMachineIpAddress; } @Override public void start() { Log.i(LOG_TAG, "start(): Starting fowarder on port: " + mPort); synchronized (this) { if (mIsRunning) { Log.w(LOG_TAG, "start(): Forwarder on port: " + mPort + " already running! NOOP."); return; } } try { mServerSocket = new ServerSocket(mPort); } catch (IOException e) { Log.e(LOG_TAG, "mPort=" + mPort, e); return; } mIsRunning = true; super.start(); } @Override public void run() { while (true) { synchronized (this) { if (!mIsRunning) { return; } /** These sockets will be closed when Forwarder.stop() is called */ Socket localSocket; Socket remoteSocket; try { localSocket = mServerSocket.accept(); remoteSocket = AdbUtils.getSocketToRemoteMachine(mRemoteMachineIpAddress, mPort); } catch (IOException e) { /** This most likely means that mServerSocket is already closed */ Log.w(LOG_TAG + "mPort=" + mPort, e); return; } if (remoteSocket == null) { try { localSocket.close(); } catch (IOException e) { Log.e(LOG_TAG, "mPort=" + mPort, e); } Log.e(LOG_TAG, "run(): mPort= " + mPort + " Failed to start forwarding from " + localSocket); continue; } ConnectionHandler forwarder = new ConnectionHandler(localSocket, remoteSocket); mConnectionHandlers.add(forwarder); forwarder.start(); } } } public void finish() { synchronized (this) { if (!mIsRunning) { return; } } try { mServerSocket.close(); } catch (IOException e) { Log.e(LOG_TAG, "mPort=" + mPort, e); } synchronized (this) { mIsRunning = false; } for (ConnectionHandler connectionHandler : mConnectionHandlers) { connectionHandler.stop(); } mConnectionHandlers.clear(); } } No newline at end of file
tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ForwarderManager.java 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * 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 java.util.HashSet; import java.util.Set; /** * A simple class to start and stop Forwarders running on some ports. * * It uses a singleton pattern and is thread safe. */ public class ForwarderManager { /** * The IP address of the server serving the tests. */ private static final String HOST_IP = "127.0.0.1"; /** * We use these ports because other webkit platforms do. They are set up in * external/webkit/LayoutTests/http/conf/apache2-debian-httpd.conf */ public static final int HTTP_PORT = 8080; public static final int HTTPS_PORT = 8443; private static ForwarderManager forwarderManager; private Set<Forwarder> mServers; private ForwarderManager() { mServers = new HashSet<Forwarder>(2); mServers.add(new Forwarder(HTTP_PORT, HOST_IP)); mServers.add(new Forwarder(HTTPS_PORT, HOST_IP)); } public static synchronized ForwarderManager getForwarderManager() { if (forwarderManager == null) { forwarderManager = new ForwarderManager(); } return forwarderManager; } @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } public synchronized void start() { for (Forwarder server : mServers) { server.start(); } } public synchronized void stop() { for (Forwarder server : mServers) { server.finish(); } } } No newline at end of file