BluetoothSocket.java revision 903ac6f399dcd4f574bf388daa7b5f5907d448d3
10b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/* 23b147b770269173d5d711d6c33f142dc5e723824zzy * Copyright (C) 2012 Google Inc. 30b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 40b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 50b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypackage android.bluetooth; 60b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 73b147b770269173d5d711d6c33f142dc5e723824zzyimport android.os.IBinder; 816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.ParcelUuid; 93b147b770269173d5d711d6c33f142dc5e723824zzyimport android.os.ParcelFileDescriptor; 1016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.RemoteException; 113b147b770269173d5d711d6c33f142dc5e723824zzyimport android.os.ServiceManager; 1216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.util.Log; 1316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 140b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.Closeable; 153b147b770269173d5d711d6c33f142dc5e723824zzyimport java.io.FileDescriptor; 163b147b770269173d5d711d6c33f142dc5e723824zzyimport java.io.FileInputStream; 173b147b770269173d5d711d6c33f142dc5e723824zzyimport java.io.FileOutputStream; 180b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.IOException; 190b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.InputStream; 200b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.OutputStream; 213b147b770269173d5d711d6c33f142dc5e723824zzyimport java.util.List; 223b147b770269173d5d711d6c33f142dc5e723824zzyimport android.net.LocalSocket; 233b147b770269173d5d711d6c33f142dc5e723824zzyimport java.nio.ByteOrder; 243b147b770269173d5d711d6c33f142dc5e723824zzyimport java.nio.ByteBuffer; 250b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/** 2645e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * A connected or connecting Bluetooth socket. 270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * 2845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets: 2945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server 3045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * side, use a {@link BluetoothServerSocket} to create a listening server 319fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * socket. When a connection is accepted by the {@link BluetoothServerSocket}, 329fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * it will return a new {@link BluetoothSocket} to manage the connection. 33f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * On the client side, use a single {@link BluetoothSocket} to both initiate 349fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * an outgoing connection and to manage the connection. 350b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * 369fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>The most common type of Bluetooth socket is RFCOMM, which is the type 379fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * supported by the Android APIs. RFCOMM is a connection-oriented, streaming 389fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * transport over Bluetooth. It is also known as the Serial Port Profile (SPP). 390b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * 409fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} for connecting to a known device, use 419fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothDevice#createRfcommSocketToServiceRecord 429fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * BluetoothDevice.createRfcommSocketToServiceRecord()}. 439fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Then call {@link #connect()} to attempt a connection to the remote device. 449fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * This call will block until a connection is established or the connection 459fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * fails. 4645e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * 479fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the 489fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothServerSocket} documentation. 4945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * 509fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>Once the socket is connected, whether initiated as a client or accepted 519fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * as a server, open the IO streams by calling {@link #getInputStream} and 529fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream} 539fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * and {@link java.io.OutputStream} objects, respectively, which are 549fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * automatically connected to the socket. 559fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * 569fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>{@link BluetoothSocket} is thread 5745e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * safe. In particular, {@link #close} will always immediately abort ongoing 5845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * operations and close the socket. 59cf44059813539bf7f36dabd278cef93ba3122c56Nick Pelly * 609fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p class="note"><strong>Note:</strong> 619fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Requires the {@link android.Manifest.permission#BLUETOOTH} permission. 629fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * 633aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <div class="special reference"> 643aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <h3>Developer Guides</h3> 653aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <p>For more information about using Bluetooth, read the 663aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p> 673aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * </div> 683aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * 699fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see BluetoothServerSocket} 709fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.InputStream} 719fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.OutputStream} 720b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 730b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypublic final class BluetoothSocket implements Closeable { 7416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static final String TAG = "BluetoothSocket"; 7516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 7624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** @hide */ 7724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public static final int MAX_RFCOMM_CHANNEL = 30; 7824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 7945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly /** Keep TYPE_ fields in sync with BluetoothSocket.cpp */ 806a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly /*package*/ static final int TYPE_RFCOMM = 1; 816a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly /*package*/ static final int TYPE_SCO = 2; 826a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly /*package*/ static final int TYPE_L2CAP = 3; 836a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly 8424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /*package*/ static final int EBADFD = 77; 8524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /*package*/ static final int EADDRINUSE = 98; 8624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 873b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ static final int SEC_FLAG_ENCRYPT = 1; 883b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ static final int SEC_FLAG_AUTH = 1 << 1; 893b147b770269173d5d711d6c33f142dc5e723824zzy 906a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly private final int mType; /* one of TYPE_RFCOMM etc */ 913b147b770269173d5d711d6c33f142dc5e723824zzy private BluetoothDevice mDevice; /* remote device */ 923b147b770269173d5d711d6c33f142dc5e723824zzy private String mAddress; /* remote address */ 930b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly private final boolean mAuth; 940b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly private final boolean mEncrypt; 950b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly private final BluetoothInputStream mInputStream; 960b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly private final BluetoothOutputStream mOutputStream; 973b147b770269173d5d711d6c33f142dc5e723824zzy private final ParcelUuid mUuid; 983b147b770269173d5d711d6c33f142dc5e723824zzy private ParcelFileDescriptor mPfd; 993b147b770269173d5d711d6c33f142dc5e723824zzy private LocalSocket mSocket; 1003b147b770269173d5d711d6c33f142dc5e723824zzy private InputStream mSocketIS; 1013b147b770269173d5d711d6c33f142dc5e723824zzy private OutputStream mSocketOS; 10216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private int mPort; /* RFCOMM channel or L2CAP psm */ 1033b147b770269173d5d711d6c33f142dc5e723824zzy private int mFd; 1043b147b770269173d5d711d6c33f142dc5e723824zzy private String mServiceName; 1053b147b770269173d5d711d6c33f142dc5e723824zzy private static int PROXY_CONNECTION_TIMEOUT = 5000; 1063b147b770269173d5d711d6c33f142dc5e723824zzy 1073b147b770269173d5d711d6c33f142dc5e723824zzy private static int SOCK_SIGNAL_SIZE = 16; 1080b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 109ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie private enum SocketState { 110ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie INIT, 111ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie CONNECTED, 1123b147b770269173d5d711d6c33f142dc5e723824zzy LISTENING, 1133b147b770269173d5d711d6c33f142dc5e723824zzy CLOSED, 114ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie } 115ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie 11671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /** prevents all native calls after destroyNative() */ 1173b147b770269173d5d711d6c33f142dc5e723824zzy private volatile SocketState mSocketState; 11871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 119ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie /** protects mSocketState */ 1203b147b770269173d5d711d6c33f142dc5e723824zzy //private final ReentrantReadWriteLock mLock; 1210b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 1220b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 123bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * Construct a BluetoothSocket. 1246a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly * @param type type of socket 1250b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param fd fd to use for connected socket, or -1 for a new socket 1260b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param auth require the remote device to be authenticated 1270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param encrypt require the connection to be encrypted 128bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param device remote device that this socket can connect to 1290b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param port remote port 13016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * @param uuid SDP uuid 1310b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @throws IOException On error, for example Bluetooth not available, or 132f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * insufficient privileges 1330b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 134bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, 13516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothDevice device, int port, ParcelUuid uuid) throws IOException { 13616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) { 13724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (port < 1 || port > MAX_RFCOMM_CHANNEL) { 13824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly throw new IOException("Invalid RFCOMM channel: " + port); 13924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 14024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 1413b147b770269173d5d711d6c33f142dc5e723824zzy mUuid = uuid; 1426a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly mType = type; 1430b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mAuth = auth; 1440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mEncrypt = encrypt; 145bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDevice = device; 1463b147b770269173d5d711d6c33f142dc5e723824zzy mPort = port; 1473b147b770269173d5d711d6c33f142dc5e723824zzy mFd = fd; 1483b147b770269173d5d711d6c33f142dc5e723824zzy 1493b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.INIT; 1503b147b770269173d5d711d6c33f142dc5e723824zzy 151bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly if (device == null) { 1523b147b770269173d5d711d6c33f142dc5e723824zzy // Server socket 1533b147b770269173d5d711d6c33f142dc5e723824zzy mAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); 154bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } else { 1553b147b770269173d5d711d6c33f142dc5e723824zzy // Remote socket 156bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAddress = device.getAddress(); 157bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 1583b147b770269173d5d711d6c33f142dc5e723824zzy mInputStream = new BluetoothInputStream(this); 1593b147b770269173d5d711d6c33f142dc5e723824zzy mOutputStream = new BluetoothOutputStream(this); 1603b147b770269173d5d711d6c33f142dc5e723824zzy } 1613b147b770269173d5d711d6c33f142dc5e723824zzy private BluetoothSocket(BluetoothSocket s) { 1623b147b770269173d5d711d6c33f142dc5e723824zzy mUuid = s.mUuid; 1633b147b770269173d5d711d6c33f142dc5e723824zzy mType = s.mType; 1643b147b770269173d5d711d6c33f142dc5e723824zzy mAuth = s.mAuth; 1653b147b770269173d5d711d6c33f142dc5e723824zzy mEncrypt = s.mEncrypt; 1663b147b770269173d5d711d6c33f142dc5e723824zzy mPort = s.mPort; 1670b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mInputStream = new BluetoothInputStream(this); 1680b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mOutputStream = new BluetoothOutputStream(this); 1693b147b770269173d5d711d6c33f142dc5e723824zzy mServiceName = s.mServiceName; 1703b147b770269173d5d711d6c33f142dc5e723824zzy } 1713b147b770269173d5d711d6c33f142dc5e723824zzy private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException { 1723b147b770269173d5d711d6c33f142dc5e723824zzy BluetoothSocket as = new BluetoothSocket(this); 1733b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocketState = SocketState.CONNECTED; 1743b147b770269173d5d711d6c33f142dc5e723824zzy FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors(); 1753b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "socket fd passed by stack fds: " + fds); 1763b147b770269173d5d711d6c33f142dc5e723824zzy if(fds == null || fds.length != 1) { 1773b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, "socket fd passed from stack failed, fds: " + fds); 1783b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket acept failed"); 1793b147b770269173d5d711d6c33f142dc5e723824zzy } 1803b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocket = new LocalSocket(fds[0]); 1813b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocketIS = as.mSocket.getInputStream(); 1823b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocketOS = as.mSocket.getOutputStream(); 1833b147b770269173d5d711d6c33f142dc5e723824zzy as.mAddress = RemoteAddr; 1843b147b770269173d5d711d6c33f142dc5e723824zzy as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(RemoteAddr); 1853b147b770269173d5d711d6c33f142dc5e723824zzy return as; 1860b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 187bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly /** 18816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Construct a BluetoothSocket from address. Used by native code. 189bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param type type of socket 190bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param fd fd to use for connected socket, or -1 for a new socket 191bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param auth require the remote device to be authenticated 192bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param encrypt require the connection to be encrypted 193bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param address remote device that this socket can connect to 194bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param port remote port 195bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @throws IOException On error, for example Bluetooth not available, or 196f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * insufficient privileges 197bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly */ 198bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, 199bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly int port) throws IOException { 20016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null); 201bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 202bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly 20345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly /** @hide */ 2040b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly @Override 2050b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly protected void finalize() throws Throwable { 2060b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly try { 2070b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly close(); 2080b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } finally { 2090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly super.finalize(); 2100b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2110b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2123b147b770269173d5d711d6c33f142dc5e723824zzy private int getSecurityFlags() { 2133b147b770269173d5d711d6c33f142dc5e723824zzy int flags = 0; 2143b147b770269173d5d711d6c33f142dc5e723824zzy if(mAuth) 2153b147b770269173d5d711d6c33f142dc5e723824zzy flags |= SEC_FLAG_AUTH; 2163b147b770269173d5d711d6c33f142dc5e723824zzy if(mEncrypt) 2173b147b770269173d5d711d6c33f142dc5e723824zzy flags |= SEC_FLAG_ENCRYPT; 2183b147b770269173d5d711d6c33f142dc5e723824zzy return flags; 2190b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2200b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2210b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 22245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * Get the remote device this socket is connecting, or connected, to. 22345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * @return remote device 2240b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 225bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public BluetoothDevice getRemoteDevice() { 226bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mDevice; 2270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2280b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2290b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 2300b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Get the input stream associated with this socket. 23145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The input stream will be returned even if the socket is not yet 2320b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * connected, but operations on that stream will throw IOException until 2330b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * the associated socket is connected. 2340b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @return InputStream 2350b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 2360b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public InputStream getInputStream() throws IOException { 2370b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly return mInputStream; 2380b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2390b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2400b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 2410b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Get the output stream associated with this socket. 24245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The output stream will be returned even if the socket is not yet 2430b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * connected, but operations on that stream will throw IOException until 2440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * the associated socket is connected. 2450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @return OutputStream 2460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 2470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public OutputStream getOutputStream() throws IOException { 2480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly return mOutputStream; 2490b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 25124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** 252ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * Get the connection status of this socket, ie, whether there is an active connection with 253ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * remote device. 254ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * @return true if connected 255ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * false if not connected 256ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie */ 257ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie public boolean isConnected() { 2583b147b770269173d5d711d6c33f142dc5e723824zzy return mSocketState == SocketState.CONNECTED; 2593b147b770269173d5d711d6c33f142dc5e723824zzy } 2603b147b770269173d5d711d6c33f142dc5e723824zzy 2613b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ void setServiceName(String name) { 2623b147b770269173d5d711d6c33f142dc5e723824zzy mServiceName = name; 2633b147b770269173d5d711d6c33f142dc5e723824zzy } 2643b147b770269173d5d711d6c33f142dc5e723824zzy 2653b147b770269173d5d711d6c33f142dc5e723824zzy /** 2663b147b770269173d5d711d6c33f142dc5e723824zzy * Attempt to connect to a remote device. 2673b147b770269173d5d711d6c33f142dc5e723824zzy * <p>This method will block until a connection is made or the connection 2683b147b770269173d5d711d6c33f142dc5e723824zzy * fails. If this method returns without an exception then this socket 2693b147b770269173d5d711d6c33f142dc5e723824zzy * is now connected. 2703b147b770269173d5d711d6c33f142dc5e723824zzy * <p>Creating new connections to 2713b147b770269173d5d711d6c33f142dc5e723824zzy * remote Bluetooth devices should not be attempted while device discovery 2723b147b770269173d5d711d6c33f142dc5e723824zzy * is in progress. Device discovery is a heavyweight procedure on the 2733b147b770269173d5d711d6c33f142dc5e723824zzy * Bluetooth adapter and will significantly slow a device connection. 2743b147b770269173d5d711d6c33f142dc5e723824zzy * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing 2753b147b770269173d5d711d6c33f142dc5e723824zzy * discovery. Discovery is not managed by the Activity, 2763b147b770269173d5d711d6c33f142dc5e723824zzy * but is run as a system service, so an application should always call 2773b147b770269173d5d711d6c33f142dc5e723824zzy * {@link BluetoothAdapter#cancelDiscovery()} even if it 2783b147b770269173d5d711d6c33f142dc5e723824zzy * did not directly request a discovery, just to be sure. 2793b147b770269173d5d711d6c33f142dc5e723824zzy * <p>{@link #close} can be used to abort this call from another thread. 2803b147b770269173d5d711d6c33f142dc5e723824zzy * @throws IOException on error, for example connection failure 2813b147b770269173d5d711d6c33f142dc5e723824zzy */ 2823b147b770269173d5d711d6c33f142dc5e723824zzy public void connect() throws IOException { 2833b147b770269173d5d711d6c33f142dc5e723824zzy if (mDevice == null) throw new IOException("Connect is called on null device"); 2843b147b770269173d5d711d6c33f142dc5e723824zzy 2853b147b770269173d5d711d6c33f142dc5e723824zzy try { 2863b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) derive flag from auth and encrypt 2873b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); 288903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null); 2890f42037eb7b5118015c2caca635538324ccf0ccffredc if (bluetoothProxy == null) throw new IOException("Bluetooth is off"); 2900f42037eb7b5118015c2caca635538324ccf0ccffredc mPfd = bluetoothProxy.connectSocket(mDevice, mType, 2913b147b770269173d5d711d6c33f142dc5e723824zzy mUuid, mPort, getSecurityFlags()); 2923b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 2933b147b770269173d5d711d6c33f142dc5e723824zzy { 2943b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 2953b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); 2963b147b770269173d5d711d6c33f142dc5e723824zzy if (mPfd == null) throw new IOException("bt socket connect failed"); 2973b147b770269173d5d711d6c33f142dc5e723824zzy FileDescriptor fd = mPfd.getFileDescriptor(); 2983b147b770269173d5d711d6c33f142dc5e723824zzy mSocket = new LocalSocket(fd); 2993b147b770269173d5d711d6c33f142dc5e723824zzy mSocketIS = mSocket.getInputStream(); 3003b147b770269173d5d711d6c33f142dc5e723824zzy mSocketOS = mSocket.getOutputStream(); 3013b147b770269173d5d711d6c33f142dc5e723824zzy } 3023b147b770269173d5d711d6c33f142dc5e723824zzy int channel = readInt(mSocketIS); 3033b147b770269173d5d711d6c33f142dc5e723824zzy if (channel <= 0) 3043b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket connect failed"); 3053b147b770269173d5d711d6c33f142dc5e723824zzy mPort = channel; 3063b147b770269173d5d711d6c33f142dc5e723824zzy waitSocketSignal(mSocketIS); 3073b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 3083b147b770269173d5d711d6c33f142dc5e723824zzy { 3093b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) 3103b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket closed"); 3113b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.CONNECTED; 3123b147b770269173d5d711d6c33f142dc5e723824zzy } 3133b147b770269173d5d711d6c33f142dc5e723824zzy } catch (RemoteException e) { 3143b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, Log.getStackTraceString(new Throwable())); 3153b147b770269173d5d711d6c33f142dc5e723824zzy } 316ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie } 317ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie 318ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie /** 31924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * Currently returns unix errno instead of throwing IOException, 32024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * so that BluetoothAdapter can check the error code for EADDRINUSE 32124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly */ 32224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /*package*/ int bindListen() { 3233b147b770269173d5d711d6c33f142dc5e723824zzy int ret; 3243b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) return EBADFD; 325903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null); 3260f42037eb7b5118015c2caca635538324ccf0ccffredc if (bluetoothProxy == null) { 3270f42037eb7b5118015c2caca635538324ccf0ccffredc Log.e(TAG, "bindListen fail, reason: bluetooth is off"); 3280f42037eb7b5118015c2caca635538324ccf0ccffredc return -1; 3290f42037eb7b5118015c2caca635538324ccf0ccffredc } 33071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 3310f42037eb7b5118015c2caca635538324ccf0ccffredc mPfd = bluetoothProxy.createSocketChannel(mType, mServiceName, 3323b147b770269173d5d711d6c33f142dc5e723824zzy mUuid, mPort, getSecurityFlags()); 3333b147b770269173d5d711d6c33f142dc5e723824zzy } catch (RemoteException e) { 3343b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, Log.getStackTraceString(new Throwable())); 3353b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) right error code? 3363b147b770269173d5d711d6c33f142dc5e723824zzy return -1; 3373b147b770269173d5d711d6c33f142dc5e723824zzy } 33871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 3393b147b770269173d5d711d6c33f142dc5e723824zzy // read out port number 34071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 3413b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) { 3423b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 3433b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState != SocketState.INIT) return EBADFD; 3443b147b770269173d5d711d6c33f142dc5e723824zzy if(mPfd == null) return -1; 3453b147b770269173d5d711d6c33f142dc5e723824zzy FileDescriptor fd = mPfd.getFileDescriptor(); 3463b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "bindListen(), new LocalSocket "); 3473b147b770269173d5d711d6c33f142dc5e723824zzy mSocket = new LocalSocket(fd); 3483b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() "); 3493b147b770269173d5d711d6c33f142dc5e723824zzy mSocketIS = mSocket.getInputStream(); 3503b147b770269173d5d711d6c33f142dc5e723824zzy mSocketOS = mSocket.getOutputStream(); 3513b147b770269173d5d711d6c33f142dc5e723824zzy } 3523b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS); 3533b147b770269173d5d711d6c33f142dc5e723824zzy int channel = readInt(mSocketIS); 3543b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) { 3553b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState == SocketState.INIT) 3563b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.LISTENING; 3573b147b770269173d5d711d6c33f142dc5e723824zzy } 3583b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "channel: " + channel); 3593b147b770269173d5d711d6c33f142dc5e723824zzy if (mPort == -1) { 3603b147b770269173d5d711d6c33f142dc5e723824zzy mPort = channel; 3613b147b770269173d5d711d6c33f142dc5e723824zzy } // else ASSERT(mPort == channel) 3623b147b770269173d5d711d6c33f142dc5e723824zzy ret = 0; 3633b147b770269173d5d711d6c33f142dc5e723824zzy } catch (IOException e) { 3643b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, "bindListen, fail to get port number, exception: " + e); 3653b147b770269173d5d711d6c33f142dc5e723824zzy return -1; 3663b147b770269173d5d711d6c33f142dc5e723824zzy } 3673b147b770269173d5d711d6c33f142dc5e723824zzy return ret; 3683b147b770269173d5d711d6c33f142dc5e723824zzy } 369ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie 3703b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ BluetoothSocket accept(int timeout) throws IOException { 3713b147b770269173d5d711d6c33f142dc5e723824zzy BluetoothSocket acceptedSocket; 3723b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState != SocketState.LISTENING) throw new IOException("bt socket is not in listen state"); 3733b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) wait on an incoming connection 3743b147b770269173d5d711d6c33f142dc5e723824zzy String RemoteAddr = waitSocketSignal(mSocketIS); 3753b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 3763b147b770269173d5d711d6c33f142dc5e723824zzy { 3773b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState != SocketState.LISTENING) 3783b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket is not in listen state"); 3793b147b770269173d5d711d6c33f142dc5e723824zzy acceptedSocket = acceptSocket(RemoteAddr); 3803b147b770269173d5d711d6c33f142dc5e723824zzy //quick drop the reference of the file handle 38171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 3823b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) rfcomm socket only supports one connection, return this? 3833b147b770269173d5d711d6c33f142dc5e723824zzy // return this; 3843b147b770269173d5d711d6c33f142dc5e723824zzy return acceptedSocket; 38571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 38671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 38771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int available() throws IOException { 3883b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "available: " + mSocketIS); 3893b147b770269173d5d711d6c33f142dc5e723824zzy return mSocketIS.available(); 39071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 39171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 39271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int read(byte[] b, int offset, int length) throws IOException { 3933b147b770269173d5d711d6c33f142dc5e723824zzy 3943b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "read in: " + mSocketIS + " len: " + length); 3953b147b770269173d5d711d6c33f142dc5e723824zzy int ret = mSocketIS.read(b, offset, length); 3963b147b770269173d5d711d6c33f142dc5e723824zzy if(ret < 0) 3973b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket closed, read return: " + ret); 3983b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); 3993b147b770269173d5d711d6c33f142dc5e723824zzy return ret; 40071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 40171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 40271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int write(byte[] b, int offset, int length) throws IOException { 4033b147b770269173d5d711d6c33f142dc5e723824zzy 4043b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "write: " + mSocketOS + " length: " + length); 4053b147b770269173d5d711d6c33f142dc5e723824zzy mSocketOS.write(b, offset, length); 4063b147b770269173d5d711d6c33f142dc5e723824zzy // There is no good way to confirm since the entire process is asynchronous anyway 4073b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "write out: " + mSocketOS + " length: " + length); 4083b147b770269173d5d711d6c33f142dc5e723824zzy return length; 4093b147b770269173d5d711d6c33f142dc5e723824zzy } 4103b147b770269173d5d711d6c33f142dc5e723824zzy 4113b147b770269173d5d711d6c33f142dc5e723824zzy @Override 4123b147b770269173d5d711d6c33f142dc5e723824zzy public void close() throws IOException { 4133b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState); 4143b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState == SocketState.CLOSED) 4153b147b770269173d5d711d6c33f142dc5e723824zzy return; 4163b147b770269173d5d711d6c33f142dc5e723824zzy else 4173b147b770269173d5d711d6c33f142dc5e723824zzy { 4183b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 4193b147b770269173d5d711d6c33f142dc5e723824zzy { 4203b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState == SocketState.CLOSED) 4213b147b770269173d5d711d6c33f142dc5e723824zzy return; 4223b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.CLOSED; 4233b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS + 4243b147b770269173d5d711d6c33f142dc5e723824zzy ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket); 4253b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocket != null) { 4263b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "Closing mSocket: " + mSocket); 4273b147b770269173d5d711d6c33f142dc5e723824zzy mSocket.shutdownInput(); 4283b147b770269173d5d711d6c33f142dc5e723824zzy mSocket.shutdownOutput(); 4293b147b770269173d5d711d6c33f142dc5e723824zzy mSocket.close(); 4303b147b770269173d5d711d6c33f142dc5e723824zzy mSocket = null; 4313b147b770269173d5d711d6c33f142dc5e723824zzy } 4323b147b770269173d5d711d6c33f142dc5e723824zzy if(mPfd != null) 4333b147b770269173d5d711d6c33f142dc5e723824zzy mPfd.detachFd(); 4343b147b770269173d5d711d6c33f142dc5e723824zzy } 43571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 4363b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) unbind proxy, 43771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 43871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 4393b147b770269173d5d711d6c33f142dc5e723824zzy /*package */ void removeChannel() { 4403b147b770269173d5d711d6c33f142dc5e723824zzy } 44116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 4423b147b770269173d5d711d6c33f142dc5e723824zzy /*package */ int getPort() { 4433b147b770269173d5d711d6c33f142dc5e723824zzy return mPort; 4443b147b770269173d5d711d6c33f142dc5e723824zzy } 4453b147b770269173d5d711d6c33f142dc5e723824zzy private String convertAddr(final byte[] addr) { 4463b147b770269173d5d711d6c33f142dc5e723824zzy return String.format("%02X:%02X:%02X:%02X:%02X:%02X", 4473b147b770269173d5d711d6c33f142dc5e723824zzy addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]); 4483b147b770269173d5d711d6c33f142dc5e723824zzy } 4493b147b770269173d5d711d6c33f142dc5e723824zzy private String waitSocketSignal(InputStream is) throws IOException { 4503b147b770269173d5d711d6c33f142dc5e723824zzy byte [] sig = new byte[SOCK_SIGNAL_SIZE]; 4513b147b770269173d5d711d6c33f142dc5e723824zzy int ret = readAll(is, sig); 4523b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "waitSocketSignal read 16 bytes signal ret: " + ret); 4533b147b770269173d5d711d6c33f142dc5e723824zzy ByteBuffer bb = ByteBuffer.wrap(sig); 4543b147b770269173d5d711d6c33f142dc5e723824zzy bb.order(ByteOrder.nativeOrder()); 4553b147b770269173d5d711d6c33f142dc5e723824zzy int size = bb.getShort(); 4563b147b770269173d5d711d6c33f142dc5e723824zzy byte [] addr = new byte[6]; 4573b147b770269173d5d711d6c33f142dc5e723824zzy bb.get(addr); 4583b147b770269173d5d711d6c33f142dc5e723824zzy int channel = bb.getInt(); 4593b147b770269173d5d711d6c33f142dc5e723824zzy int status = bb.getInt(); 4603b147b770269173d5d711d6c33f142dc5e723824zzy String RemoteAddr = convertAddr(addr); 4613b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: " 4623b147b770269173d5d711d6c33f142dc5e723824zzy + RemoteAddr + ", channel: " + channel + ", status: " + status); 4633b147b770269173d5d711d6c33f142dc5e723824zzy if(status != 0) 4643b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("Connection failure, status: " + status); 4653b147b770269173d5d711d6c33f142dc5e723824zzy return RemoteAddr; 4663b147b770269173d5d711d6c33f142dc5e723824zzy } 4673b147b770269173d5d711d6c33f142dc5e723824zzy private int readAll(InputStream is, byte[] b) throws IOException { 4683b147b770269173d5d711d6c33f142dc5e723824zzy int left = b.length; 4693b147b770269173d5d711d6c33f142dc5e723824zzy while(left > 0) { 4703b147b770269173d5d711d6c33f142dc5e723824zzy int ret = is.read(b, b.length - left, left); 4713b147b770269173d5d711d6c33f142dc5e723824zzy if(ret < 0) 4723b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("read failed, socket might closed, read ret: " + ret); 4733b147b770269173d5d711d6c33f142dc5e723824zzy left -= ret; 4743b147b770269173d5d711d6c33f142dc5e723824zzy if(left != 0) 4753b147b770269173d5d711d6c33f142dc5e723824zzy Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) + 4763b147b770269173d5d711d6c33f142dc5e723824zzy ", expect size: " + b.length); 47716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 4783b147b770269173d5d711d6c33f142dc5e723824zzy return b.length; 4793b147b770269173d5d711d6c33f142dc5e723824zzy } 4803b147b770269173d5d711d6c33f142dc5e723824zzy 4813b147b770269173d5d711d6c33f142dc5e723824zzy private int readInt(InputStream is) throws IOException { 4823b147b770269173d5d711d6c33f142dc5e723824zzy byte[] ibytes = new byte[4]; 4833b147b770269173d5d711d6c33f142dc5e723824zzy int ret = readAll(is, ibytes); 4843b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "inputStream.read ret: " + ret); 4853b147b770269173d5d711d6c33f142dc5e723824zzy ByteBuffer bb = ByteBuffer.wrap(ibytes); 4863b147b770269173d5d711d6c33f142dc5e723824zzy bb.order(ByteOrder.nativeOrder()); 4873b147b770269173d5d711d6c33f142dc5e723824zzy return bb.getInt(); 48816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 4890b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly} 490