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