BluetoothSocket.java revision 3b147b770269173d5d711d6c33f142dc5e723824
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 IBluetooth sBluetoothProxy; 1063b147b770269173d5d711d6c33f142dc5e723824zzy private static int PROXY_CONNECTION_TIMEOUT = 5000; 1073b147b770269173d5d711d6c33f142dc5e723824zzy 1083b147b770269173d5d711d6c33f142dc5e723824zzy private static int SOCK_SIGNAL_SIZE = 16; 1090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 110ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie private enum SocketState { 111ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie INIT, 112ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie CONNECTED, 1133b147b770269173d5d711d6c33f142dc5e723824zzy LISTENING, 1143b147b770269173d5d711d6c33f142dc5e723824zzy CLOSED, 115ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie } 116ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie 11771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /** prevents all native calls after destroyNative() */ 1183b147b770269173d5d711d6c33f142dc5e723824zzy private volatile SocketState mSocketState; 11971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 120ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie /** protects mSocketState */ 1213b147b770269173d5d711d6c33f142dc5e723824zzy //private final ReentrantReadWriteLock mLock; 1220b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 1230b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 124bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * Construct a BluetoothSocket. 1256a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly * @param type type of socket 1260b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param fd fd to use for connected socket, or -1 for a new socket 1270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param auth require the remote device to be authenticated 1280b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param encrypt require the connection to be encrypted 129bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param device remote device that this socket can connect to 1300b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param port remote port 13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * @param uuid SDP uuid 1320b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @throws IOException On error, for example Bluetooth not available, or 133f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * insufficient privileges 1340b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 135bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, 13616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothDevice device, int port, ParcelUuid uuid) throws IOException { 13716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) { 13824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (port < 1 || port > MAX_RFCOMM_CHANNEL) { 13924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly throw new IOException("Invalid RFCOMM channel: " + port); 14024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 14124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 1423b147b770269173d5d711d6c33f142dc5e723824zzy mUuid = uuid; 1436a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly mType = type; 1440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mAuth = auth; 1450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mEncrypt = encrypt; 146bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDevice = device; 1473b147b770269173d5d711d6c33f142dc5e723824zzy mPort = port; 1483b147b770269173d5d711d6c33f142dc5e723824zzy mFd = fd; 1493b147b770269173d5d711d6c33f142dc5e723824zzy 1503b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.INIT; 1513b147b770269173d5d711d6c33f142dc5e723824zzy 152bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly if (device == null) { 1533b147b770269173d5d711d6c33f142dc5e723824zzy // Server socket 1543b147b770269173d5d711d6c33f142dc5e723824zzy mAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); 155bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } else { 1563b147b770269173d5d711d6c33f142dc5e723824zzy // Remote socket 157bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAddress = device.getAddress(); 158bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 1593b147b770269173d5d711d6c33f142dc5e723824zzy mInputStream = new BluetoothInputStream(this); 1603b147b770269173d5d711d6c33f142dc5e723824zzy mOutputStream = new BluetoothOutputStream(this); 161e4caddbb7a3b39fd6a1ccf107c7dbf09bc8978e8Jaikumar Ganesh 1623b147b770269173d5d711d6c33f142dc5e723824zzy if (sBluetoothProxy == null) { 1633b147b770269173d5d711d6c33f142dc5e723824zzy synchronized (BluetoothSocket.class) { 1643b147b770269173d5d711d6c33f142dc5e723824zzy if (sBluetoothProxy == null) { 1653b147b770269173d5d711d6c33f142dc5e723824zzy IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE); 1663b147b770269173d5d711d6c33f142dc5e723824zzy if (b == null) 1673b147b770269173d5d711d6c33f142dc5e723824zzy throw new RuntimeException("Bluetooth service not available"); 1683b147b770269173d5d711d6c33f142dc5e723824zzy sBluetoothProxy = IBluetooth.Stub.asInterface(b); 1693b147b770269173d5d711d6c33f142dc5e723824zzy } 1703b147b770269173d5d711d6c33f142dc5e723824zzy } 1713b147b770269173d5d711d6c33f142dc5e723824zzy } 1723b147b770269173d5d711d6c33f142dc5e723824zzy } 1733b147b770269173d5d711d6c33f142dc5e723824zzy private BluetoothSocket(BluetoothSocket s) { 1743b147b770269173d5d711d6c33f142dc5e723824zzy mUuid = s.mUuid; 1753b147b770269173d5d711d6c33f142dc5e723824zzy mType = s.mType; 1763b147b770269173d5d711d6c33f142dc5e723824zzy mAuth = s.mAuth; 1773b147b770269173d5d711d6c33f142dc5e723824zzy mEncrypt = s.mEncrypt; 1783b147b770269173d5d711d6c33f142dc5e723824zzy mPort = s.mPort; 1790b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mInputStream = new BluetoothInputStream(this); 1800b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mOutputStream = new BluetoothOutputStream(this); 1813b147b770269173d5d711d6c33f142dc5e723824zzy mServiceName = s.mServiceName; 1823b147b770269173d5d711d6c33f142dc5e723824zzy } 1833b147b770269173d5d711d6c33f142dc5e723824zzy private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException { 1843b147b770269173d5d711d6c33f142dc5e723824zzy BluetoothSocket as = new BluetoothSocket(this); 1853b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocketState = SocketState.CONNECTED; 1863b147b770269173d5d711d6c33f142dc5e723824zzy FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors(); 1873b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "socket fd passed by stack fds: " + fds); 1883b147b770269173d5d711d6c33f142dc5e723824zzy if(fds == null || fds.length != 1) { 1893b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, "socket fd passed from stack failed, fds: " + fds); 1903b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket acept failed"); 1913b147b770269173d5d711d6c33f142dc5e723824zzy } 1923b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocket = new LocalSocket(fds[0]); 1933b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocketIS = as.mSocket.getInputStream(); 1943b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocketOS = as.mSocket.getOutputStream(); 1953b147b770269173d5d711d6c33f142dc5e723824zzy as.mAddress = RemoteAddr; 1963b147b770269173d5d711d6c33f142dc5e723824zzy as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(RemoteAddr); 1973b147b770269173d5d711d6c33f142dc5e723824zzy return as; 1980b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 199bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly /** 20016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Construct a BluetoothSocket from address. Used by native code. 201bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param type type of socket 202bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param fd fd to use for connected socket, or -1 for a new socket 203bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param auth require the remote device to be authenticated 204bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param encrypt require the connection to be encrypted 205bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param address remote device that this socket can connect to 206bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param port remote port 207bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @throws IOException On error, for example Bluetooth not available, or 208f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * insufficient privileges 209bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly */ 210bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, 211bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly int port) throws IOException { 21216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null); 213bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 214bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly 21545e2704ff512d41e22af2801d76e96955469ce8dNick Pelly /** @hide */ 2160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly @Override 2170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly protected void finalize() throws Throwable { 2180b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly try { 2190b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly close(); 2200b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } finally { 2210b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly super.finalize(); 2220b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2230b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2243b147b770269173d5d711d6c33f142dc5e723824zzy private int getSecurityFlags() { 2253b147b770269173d5d711d6c33f142dc5e723824zzy int flags = 0; 2263b147b770269173d5d711d6c33f142dc5e723824zzy if(mAuth) 2273b147b770269173d5d711d6c33f142dc5e723824zzy flags |= SEC_FLAG_AUTH; 2283b147b770269173d5d711d6c33f142dc5e723824zzy if(mEncrypt) 2293b147b770269173d5d711d6c33f142dc5e723824zzy flags |= SEC_FLAG_ENCRYPT; 2303b147b770269173d5d711d6c33f142dc5e723824zzy return flags; 2310b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2320b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2330b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 23445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * Get the remote device this socket is connecting, or connected, to. 23545e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * @return remote device 2360b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 237bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public BluetoothDevice getRemoteDevice() { 238bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mDevice; 2390b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2400b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2410b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 2420b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Get the input stream associated with this socket. 24345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The input stream will be returned even if the socket is not yet 2440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * connected, but operations on that stream will throw IOException until 2450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * the associated socket is connected. 2460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @return InputStream 2470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 2480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public InputStream getInputStream() throws IOException { 2490b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly return mInputStream; 2500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2510b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 2530b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Get the output stream associated with this socket. 25445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The output stream will be returned even if the socket is not yet 2550b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * connected, but operations on that stream will throw IOException until 2560b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * the associated socket is connected. 2570b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @return OutputStream 2580b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 2590b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public OutputStream getOutputStream() throws IOException { 2600b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly return mOutputStream; 2610b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2620b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 26324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** 264ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * Get the connection status of this socket, ie, whether there is an active connection with 265ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * remote device. 266ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * @return true if connected 267ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * false if not connected 268ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie */ 269ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie public boolean isConnected() { 2703b147b770269173d5d711d6c33f142dc5e723824zzy return mSocketState == SocketState.CONNECTED; 2713b147b770269173d5d711d6c33f142dc5e723824zzy } 2723b147b770269173d5d711d6c33f142dc5e723824zzy 2733b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ void setServiceName(String name) { 2743b147b770269173d5d711d6c33f142dc5e723824zzy mServiceName = name; 2753b147b770269173d5d711d6c33f142dc5e723824zzy } 2763b147b770269173d5d711d6c33f142dc5e723824zzy 2773b147b770269173d5d711d6c33f142dc5e723824zzy /** 2783b147b770269173d5d711d6c33f142dc5e723824zzy * Attempt to connect to a remote device. 2793b147b770269173d5d711d6c33f142dc5e723824zzy * <p>This method will block until a connection is made or the connection 2803b147b770269173d5d711d6c33f142dc5e723824zzy * fails. If this method returns without an exception then this socket 2813b147b770269173d5d711d6c33f142dc5e723824zzy * is now connected. 2823b147b770269173d5d711d6c33f142dc5e723824zzy * <p>Creating new connections to 2833b147b770269173d5d711d6c33f142dc5e723824zzy * remote Bluetooth devices should not be attempted while device discovery 2843b147b770269173d5d711d6c33f142dc5e723824zzy * is in progress. Device discovery is a heavyweight procedure on the 2853b147b770269173d5d711d6c33f142dc5e723824zzy * Bluetooth adapter and will significantly slow a device connection. 2863b147b770269173d5d711d6c33f142dc5e723824zzy * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing 2873b147b770269173d5d711d6c33f142dc5e723824zzy * discovery. Discovery is not managed by the Activity, 2883b147b770269173d5d711d6c33f142dc5e723824zzy * but is run as a system service, so an application should always call 2893b147b770269173d5d711d6c33f142dc5e723824zzy * {@link BluetoothAdapter#cancelDiscovery()} even if it 2903b147b770269173d5d711d6c33f142dc5e723824zzy * did not directly request a discovery, just to be sure. 2913b147b770269173d5d711d6c33f142dc5e723824zzy * <p>{@link #close} can be used to abort this call from another thread. 2923b147b770269173d5d711d6c33f142dc5e723824zzy * @throws IOException on error, for example connection failure 2933b147b770269173d5d711d6c33f142dc5e723824zzy */ 2943b147b770269173d5d711d6c33f142dc5e723824zzy public void connect() throws IOException { 2953b147b770269173d5d711d6c33f142dc5e723824zzy if (mDevice == null) throw new IOException("Connect is called on null device"); 2963b147b770269173d5d711d6c33f142dc5e723824zzy 2973b147b770269173d5d711d6c33f142dc5e723824zzy try { 2983b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) derive flag from auth and encrypt 2993b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); 3003b147b770269173d5d711d6c33f142dc5e723824zzy 3013b147b770269173d5d711d6c33f142dc5e723824zzy mPfd = sBluetoothProxy.connectSocket(mDevice, mType, 3023b147b770269173d5d711d6c33f142dc5e723824zzy mUuid, mPort, getSecurityFlags()); 3033b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 3043b147b770269173d5d711d6c33f142dc5e723824zzy { 3053b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 3063b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); 3073b147b770269173d5d711d6c33f142dc5e723824zzy if (mPfd == null) throw new IOException("bt socket connect failed"); 3083b147b770269173d5d711d6c33f142dc5e723824zzy FileDescriptor fd = mPfd.getFileDescriptor(); 3093b147b770269173d5d711d6c33f142dc5e723824zzy mSocket = new LocalSocket(fd); 3103b147b770269173d5d711d6c33f142dc5e723824zzy mSocketIS = mSocket.getInputStream(); 3113b147b770269173d5d711d6c33f142dc5e723824zzy mSocketOS = mSocket.getOutputStream(); 3123b147b770269173d5d711d6c33f142dc5e723824zzy } 3133b147b770269173d5d711d6c33f142dc5e723824zzy int channel = readInt(mSocketIS); 3143b147b770269173d5d711d6c33f142dc5e723824zzy if (channel <= 0) 3153b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket connect failed"); 3163b147b770269173d5d711d6c33f142dc5e723824zzy mPort = channel; 3173b147b770269173d5d711d6c33f142dc5e723824zzy waitSocketSignal(mSocketIS); 3183b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 3193b147b770269173d5d711d6c33f142dc5e723824zzy { 3203b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) 3213b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket closed"); 3223b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.CONNECTED; 3233b147b770269173d5d711d6c33f142dc5e723824zzy } 3243b147b770269173d5d711d6c33f142dc5e723824zzy } catch (RemoteException e) { 3253b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, Log.getStackTraceString(new Throwable())); 3263b147b770269173d5d711d6c33f142dc5e723824zzy } 327ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie } 328ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie 329ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie /** 33024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * Currently returns unix errno instead of throwing IOException, 33124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * so that BluetoothAdapter can check the error code for EADDRINUSE 33224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly */ 33324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /*package*/ int bindListen() { 3343b147b770269173d5d711d6c33f142dc5e723824zzy int ret; 3353b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) return EBADFD; 33671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 3373b147b770269173d5d711d6c33f142dc5e723824zzy mPfd = sBluetoothProxy.createSocketChannel(mType, mServiceName, 3383b147b770269173d5d711d6c33f142dc5e723824zzy mUuid, mPort, getSecurityFlags()); 3393b147b770269173d5d711d6c33f142dc5e723824zzy } catch (RemoteException e) { 3403b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, Log.getStackTraceString(new Throwable())); 3413b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) right error code? 3423b147b770269173d5d711d6c33f142dc5e723824zzy return -1; 3433b147b770269173d5d711d6c33f142dc5e723824zzy } 34471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 3453b147b770269173d5d711d6c33f142dc5e723824zzy // read out port number 34671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 3473b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) { 3483b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 3493b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState != SocketState.INIT) return EBADFD; 3503b147b770269173d5d711d6c33f142dc5e723824zzy if(mPfd == null) return -1; 3513b147b770269173d5d711d6c33f142dc5e723824zzy FileDescriptor fd = mPfd.getFileDescriptor(); 3523b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "bindListen(), new LocalSocket "); 3533b147b770269173d5d711d6c33f142dc5e723824zzy mSocket = new LocalSocket(fd); 3543b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() "); 3553b147b770269173d5d711d6c33f142dc5e723824zzy mSocketIS = mSocket.getInputStream(); 3563b147b770269173d5d711d6c33f142dc5e723824zzy mSocketOS = mSocket.getOutputStream(); 3573b147b770269173d5d711d6c33f142dc5e723824zzy } 3583b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS); 3593b147b770269173d5d711d6c33f142dc5e723824zzy int channel = readInt(mSocketIS); 3603b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) { 3613b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState == SocketState.INIT) 3623b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.LISTENING; 3633b147b770269173d5d711d6c33f142dc5e723824zzy } 3643b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "channel: " + channel); 3653b147b770269173d5d711d6c33f142dc5e723824zzy if (mPort == -1) { 3663b147b770269173d5d711d6c33f142dc5e723824zzy mPort = channel; 3673b147b770269173d5d711d6c33f142dc5e723824zzy } // else ASSERT(mPort == channel) 3683b147b770269173d5d711d6c33f142dc5e723824zzy ret = 0; 3693b147b770269173d5d711d6c33f142dc5e723824zzy } catch (IOException e) { 3703b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, "bindListen, fail to get port number, exception: " + e); 3713b147b770269173d5d711d6c33f142dc5e723824zzy return -1; 3723b147b770269173d5d711d6c33f142dc5e723824zzy } 3733b147b770269173d5d711d6c33f142dc5e723824zzy return ret; 3743b147b770269173d5d711d6c33f142dc5e723824zzy } 375ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie 3763b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ BluetoothSocket accept(int timeout) throws IOException { 3773b147b770269173d5d711d6c33f142dc5e723824zzy BluetoothSocket acceptedSocket; 3783b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState != SocketState.LISTENING) throw new IOException("bt socket is not in listen state"); 3793b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) wait on an incoming connection 3803b147b770269173d5d711d6c33f142dc5e723824zzy String RemoteAddr = waitSocketSignal(mSocketIS); 3813b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 3823b147b770269173d5d711d6c33f142dc5e723824zzy { 3833b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState != SocketState.LISTENING) 3843b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket is not in listen state"); 3853b147b770269173d5d711d6c33f142dc5e723824zzy acceptedSocket = acceptSocket(RemoteAddr); 3863b147b770269173d5d711d6c33f142dc5e723824zzy //quick drop the reference of the file handle 38771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 3883b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) rfcomm socket only supports one connection, return this? 3893b147b770269173d5d711d6c33f142dc5e723824zzy // return this; 3903b147b770269173d5d711d6c33f142dc5e723824zzy return acceptedSocket; 39171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 39271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 39371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int available() throws IOException { 3943b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "available: " + mSocketIS); 3953b147b770269173d5d711d6c33f142dc5e723824zzy return mSocketIS.available(); 39671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 39771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 39871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int read(byte[] b, int offset, int length) throws IOException { 3993b147b770269173d5d711d6c33f142dc5e723824zzy 4003b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "read in: " + mSocketIS + " len: " + length); 4013b147b770269173d5d711d6c33f142dc5e723824zzy int ret = mSocketIS.read(b, offset, length); 4023b147b770269173d5d711d6c33f142dc5e723824zzy if(ret < 0) 4033b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket closed, read return: " + ret); 4043b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); 4053b147b770269173d5d711d6c33f142dc5e723824zzy return ret; 40671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 40771c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 40871c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int write(byte[] b, int offset, int length) throws IOException { 4093b147b770269173d5d711d6c33f142dc5e723824zzy 4103b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "write: " + mSocketOS + " length: " + length); 4113b147b770269173d5d711d6c33f142dc5e723824zzy mSocketOS.write(b, offset, length); 4123b147b770269173d5d711d6c33f142dc5e723824zzy // There is no good way to confirm since the entire process is asynchronous anyway 4133b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "write out: " + mSocketOS + " length: " + length); 4143b147b770269173d5d711d6c33f142dc5e723824zzy return length; 4153b147b770269173d5d711d6c33f142dc5e723824zzy } 4163b147b770269173d5d711d6c33f142dc5e723824zzy 4173b147b770269173d5d711d6c33f142dc5e723824zzy @Override 4183b147b770269173d5d711d6c33f142dc5e723824zzy public void close() throws IOException { 4193b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState); 4203b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState == SocketState.CLOSED) 4213b147b770269173d5d711d6c33f142dc5e723824zzy return; 4223b147b770269173d5d711d6c33f142dc5e723824zzy else 4233b147b770269173d5d711d6c33f142dc5e723824zzy { 4243b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 4253b147b770269173d5d711d6c33f142dc5e723824zzy { 4263b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState == SocketState.CLOSED) 4273b147b770269173d5d711d6c33f142dc5e723824zzy return; 4283b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.CLOSED; 4293b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS + 4303b147b770269173d5d711d6c33f142dc5e723824zzy ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket); 4313b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocket != null) { 4323b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "Closing mSocket: " + mSocket); 4333b147b770269173d5d711d6c33f142dc5e723824zzy mSocket.shutdownInput(); 4343b147b770269173d5d711d6c33f142dc5e723824zzy mSocket.shutdownOutput(); 4353b147b770269173d5d711d6c33f142dc5e723824zzy mSocket.close(); 4363b147b770269173d5d711d6c33f142dc5e723824zzy mSocket = null; 4373b147b770269173d5d711d6c33f142dc5e723824zzy } 4383b147b770269173d5d711d6c33f142dc5e723824zzy if(mPfd != null) 4393b147b770269173d5d711d6c33f142dc5e723824zzy mPfd.detachFd(); 4403b147b770269173d5d711d6c33f142dc5e723824zzy } 44171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 4423b147b770269173d5d711d6c33f142dc5e723824zzy // TODO(BT) unbind proxy, 44371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 44471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 4453b147b770269173d5d711d6c33f142dc5e723824zzy /*package */ void removeChannel() { 4463b147b770269173d5d711d6c33f142dc5e723824zzy } 44716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 4483b147b770269173d5d711d6c33f142dc5e723824zzy /*package */ int getPort() { 4493b147b770269173d5d711d6c33f142dc5e723824zzy return mPort; 4503b147b770269173d5d711d6c33f142dc5e723824zzy } 4513b147b770269173d5d711d6c33f142dc5e723824zzy private String convertAddr(final byte[] addr) { 4523b147b770269173d5d711d6c33f142dc5e723824zzy return String.format("%02X:%02X:%02X:%02X:%02X:%02X", 4533b147b770269173d5d711d6c33f142dc5e723824zzy addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]); 4543b147b770269173d5d711d6c33f142dc5e723824zzy } 4553b147b770269173d5d711d6c33f142dc5e723824zzy private String waitSocketSignal(InputStream is) throws IOException { 4563b147b770269173d5d711d6c33f142dc5e723824zzy byte [] sig = new byte[SOCK_SIGNAL_SIZE]; 4573b147b770269173d5d711d6c33f142dc5e723824zzy int ret = readAll(is, sig); 4583b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "waitSocketSignal read 16 bytes signal ret: " + ret); 4593b147b770269173d5d711d6c33f142dc5e723824zzy ByteBuffer bb = ByteBuffer.wrap(sig); 4603b147b770269173d5d711d6c33f142dc5e723824zzy bb.order(ByteOrder.nativeOrder()); 4613b147b770269173d5d711d6c33f142dc5e723824zzy int size = bb.getShort(); 4623b147b770269173d5d711d6c33f142dc5e723824zzy byte [] addr = new byte[6]; 4633b147b770269173d5d711d6c33f142dc5e723824zzy bb.get(addr); 4643b147b770269173d5d711d6c33f142dc5e723824zzy int channel = bb.getInt(); 4653b147b770269173d5d711d6c33f142dc5e723824zzy int status = bb.getInt(); 4663b147b770269173d5d711d6c33f142dc5e723824zzy String RemoteAddr = convertAddr(addr); 4673b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: " 4683b147b770269173d5d711d6c33f142dc5e723824zzy + RemoteAddr + ", channel: " + channel + ", status: " + status); 4693b147b770269173d5d711d6c33f142dc5e723824zzy if(status != 0) 4703b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("Connection failure, status: " + status); 4713b147b770269173d5d711d6c33f142dc5e723824zzy return RemoteAddr; 4723b147b770269173d5d711d6c33f142dc5e723824zzy } 4733b147b770269173d5d711d6c33f142dc5e723824zzy private int readAll(InputStream is, byte[] b) throws IOException { 4743b147b770269173d5d711d6c33f142dc5e723824zzy int left = b.length; 4753b147b770269173d5d711d6c33f142dc5e723824zzy while(left > 0) { 4763b147b770269173d5d711d6c33f142dc5e723824zzy int ret = is.read(b, b.length - left, left); 4773b147b770269173d5d711d6c33f142dc5e723824zzy if(ret < 0) 4783b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("read failed, socket might closed, read ret: " + ret); 4793b147b770269173d5d711d6c33f142dc5e723824zzy left -= ret; 4803b147b770269173d5d711d6c33f142dc5e723824zzy if(left != 0) 4813b147b770269173d5d711d6c33f142dc5e723824zzy Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) + 4823b147b770269173d5d711d6c33f142dc5e723824zzy ", expect size: " + b.length); 48316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 4843b147b770269173d5d711d6c33f142dc5e723824zzy return b.length; 4853b147b770269173d5d711d6c33f142dc5e723824zzy } 4863b147b770269173d5d711d6c33f142dc5e723824zzy 4873b147b770269173d5d711d6c33f142dc5e723824zzy private int readInt(InputStream is) throws IOException { 4883b147b770269173d5d711d6c33f142dc5e723824zzy byte[] ibytes = new byte[4]; 4893b147b770269173d5d711d6c33f142dc5e723824zzy int ret = readAll(is, ibytes); 4903b147b770269173d5d711d6c33f142dc5e723824zzy Log.d(TAG, "inputStream.read ret: " + ret); 4913b147b770269173d5d711d6c33f142dc5e723824zzy ByteBuffer bb = ByteBuffer.wrap(ibytes); 4923b147b770269173d5d711d6c33f142dc5e723824zzy bb.order(ByteOrder.nativeOrder()); 4933b147b770269173d5d711d6c33f142dc5e723824zzy return bb.getInt(); 49416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 4950b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly} 496