10b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/* 2fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * Copyright (C) 2012 The Android Open Source Project 3fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * 4fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * Licensed under the Apache License, Version 2.0 (the "License"); 5fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * you may not use this file except in compliance with the License. 6fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * You may obtain a copy of the License at 7fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * 8fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * http://www.apache.org/licenses/LICENSE-2.0 9fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * 10fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * Unless required by applicable law or agreed to in writing, software 11fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * distributed under the License is distributed on an "AS IS" BASIS, 12fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * See the License for the specific language governing permissions and 14fa0fd39a4bf296d254aa398c1b19ec960efa641dZhihai Xu * limitations under the License. 150b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 160b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 170b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypackage android.bluetooth; 180b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 193b147b770269173d5d711d6c33f142dc5e723824zzyimport android.os.IBinder; 2016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.ParcelUuid; 213b147b770269173d5d711d6c33f142dc5e723824zzyimport android.os.ParcelFileDescriptor; 2216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.os.RemoteException; 233b147b770269173d5d711d6c33f142dc5e723824zzyimport android.os.ServiceManager; 2416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.util.Log; 2516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 260b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.Closeable; 273b147b770269173d5d711d6c33f142dc5e723824zzyimport java.io.FileDescriptor; 283b147b770269173d5d711d6c33f142dc5e723824zzyimport java.io.FileInputStream; 293b147b770269173d5d711d6c33f142dc5e723824zzyimport java.io.FileOutputStream; 300b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.IOException; 310b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.InputStream; 320b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellyimport java.io.OutputStream; 333b147b770269173d5d711d6c33f142dc5e723824zzyimport java.util.List; 34b49a89635906e0901637a4a4c1c2f5bb263b6595zzyimport java.util.UUID; 353b147b770269173d5d711d6c33f142dc5e723824zzyimport android.net.LocalSocket; 363b147b770269173d5d711d6c33f142dc5e723824zzyimport java.nio.ByteOrder; 373b147b770269173d5d711d6c33f142dc5e723824zzyimport java.nio.ByteBuffer; 380b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly/** 3945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * A connected or connecting Bluetooth socket. 400b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * 4145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets: 4245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server 4345e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * side, use a {@link BluetoothServerSocket} to create a listening server 449fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * socket. When a connection is accepted by the {@link BluetoothServerSocket}, 459fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * it will return a new {@link BluetoothSocket} to manage the connection. 46f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * On the client side, use a single {@link BluetoothSocket} to both initiate 479fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * an outgoing connection and to manage the connection. 480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * 499fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>The most common type of Bluetooth socket is RFCOMM, which is the type 509fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * supported by the Android APIs. RFCOMM is a connection-oriented, streaming 519fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * transport over Bluetooth. It is also known as the Serial Port Profile (SPP). 520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * 539fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} for connecting to a known device, use 549fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothDevice#createRfcommSocketToServiceRecord 559fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * BluetoothDevice.createRfcommSocketToServiceRecord()}. 569fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Then call {@link #connect()} to attempt a connection to the remote device. 579fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * This call will block until a connection is established or the connection 589fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * fails. 5945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * 609fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the 619fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link BluetoothServerSocket} documentation. 6245e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * 639fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>Once the socket is connected, whether initiated as a client or accepted 649fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * as a server, open the IO streams by calling {@link #getInputStream} and 659fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream} 669fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * and {@link java.io.OutputStream} objects, respectively, which are 679fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * automatically connected to the socket. 689fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * 699fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p>{@link BluetoothSocket} is thread 7045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * safe. In particular, {@link #close} will always immediately abort ongoing 7145e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * operations and close the socket. 72cf44059813539bf7f36dabd278cef93ba3122c56Nick Pelly * 739fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * <p class="note"><strong>Note:</strong> 749fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * Requires the {@link android.Manifest.permission#BLUETOOTH} permission. 759fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * 763aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <div class="special reference"> 773aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <h3>Developer Guides</h3> 783aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <p>For more information about using Bluetooth, read the 793aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p> 803aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * </div> 813aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * 829fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see BluetoothServerSocket} 839fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.InputStream} 849fab0aef19a4633d2e4670564e5d7ae9e52fe11fScott Main * {@see java.io.OutputStream} 850b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 860b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pellypublic final class BluetoothSocket implements Closeable { 8716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static final String TAG = "BluetoothSocket"; 88563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie private static final boolean DBG = true; 89563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie private static final boolean VDBG = false; 9016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 9124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** @hide */ 9224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public static final int MAX_RFCOMM_CHANNEL = 30; 9324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 9445e2704ff512d41e22af2801d76e96955469ce8dNick Pelly /** Keep TYPE_ fields in sync with BluetoothSocket.cpp */ 956a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly /*package*/ static final int TYPE_RFCOMM = 1; 966a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly /*package*/ static final int TYPE_SCO = 2; 976a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly /*package*/ static final int TYPE_L2CAP = 3; 986a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly 9924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /*package*/ static final int EBADFD = 77; 10024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /*package*/ static final int EADDRINUSE = 98; 10124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 1023b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ static final int SEC_FLAG_ENCRYPT = 1; 1033b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ static final int SEC_FLAG_AUTH = 1 << 1; 1043b147b770269173d5d711d6c33f142dc5e723824zzy 1056a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly private final int mType; /* one of TYPE_RFCOMM etc */ 1063b147b770269173d5d711d6c33f142dc5e723824zzy private BluetoothDevice mDevice; /* remote device */ 1073b147b770269173d5d711d6c33f142dc5e723824zzy private String mAddress; /* remote address */ 1080b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly private final boolean mAuth; 1090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly private final boolean mEncrypt; 1100b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly private final BluetoothInputStream mInputStream; 1110b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly private final BluetoothOutputStream mOutputStream; 1123b147b770269173d5d711d6c33f142dc5e723824zzy private final ParcelUuid mUuid; 1133b147b770269173d5d711d6c33f142dc5e723824zzy private ParcelFileDescriptor mPfd; 1143b147b770269173d5d711d6c33f142dc5e723824zzy private LocalSocket mSocket; 1153b147b770269173d5d711d6c33f142dc5e723824zzy private InputStream mSocketIS; 1163b147b770269173d5d711d6c33f142dc5e723824zzy private OutputStream mSocketOS; 11716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private int mPort; /* RFCOMM channel or L2CAP psm */ 1183b147b770269173d5d711d6c33f142dc5e723824zzy private int mFd; 1193b147b770269173d5d711d6c33f142dc5e723824zzy private String mServiceName; 1203b147b770269173d5d711d6c33f142dc5e723824zzy private static int PROXY_CONNECTION_TIMEOUT = 5000; 1213b147b770269173d5d711d6c33f142dc5e723824zzy 1223b147b770269173d5d711d6c33f142dc5e723824zzy private static int SOCK_SIGNAL_SIZE = 16; 1230b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 124ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie private enum SocketState { 125ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie INIT, 126ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie CONNECTED, 1273b147b770269173d5d711d6c33f142dc5e723824zzy LISTENING, 1283b147b770269173d5d711d6c33f142dc5e723824zzy CLOSED, 129ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie } 130ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie 13171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /** prevents all native calls after destroyNative() */ 1323b147b770269173d5d711d6c33f142dc5e723824zzy private volatile SocketState mSocketState; 13371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 134ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie /** protects mSocketState */ 1353b147b770269173d5d711d6c33f142dc5e723824zzy //private final ReentrantReadWriteLock mLock; 1360b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 1370b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 138bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * Construct a BluetoothSocket. 1396a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly * @param type type of socket 1400b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param fd fd to use for connected socket, or -1 for a new socket 1410b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param auth require the remote device to be authenticated 1420b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param encrypt require the connection to be encrypted 143bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param device remote device that this socket can connect to 1440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @param port remote port 14516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * @param uuid SDP uuid 1460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @throws IOException On error, for example Bluetooth not available, or 147f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * insufficient privileges 1480b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 149bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, 15016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothDevice device, int port, ParcelUuid uuid) throws IOException { 15116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) { 15224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (port < 1 || port > MAX_RFCOMM_CHANNEL) { 15324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly throw new IOException("Invalid RFCOMM channel: " + port); 15424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 15524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 156b49a89635906e0901637a4a4c1c2f5bb263b6595zzy if(uuid != null) 157b49a89635906e0901637a4a4c1c2f5bb263b6595zzy mUuid = uuid; 158b49a89635906e0901637a4a4c1c2f5bb263b6595zzy else mUuid = new ParcelUuid(new UUID(0, 0)); 1596a669fac385b51b8bb01844b77a9a43840dda854Nick Pelly mType = type; 1600b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mAuth = auth; 1610b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mEncrypt = encrypt; 162bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDevice = device; 1633b147b770269173d5d711d6c33f142dc5e723824zzy mPort = port; 1643b147b770269173d5d711d6c33f142dc5e723824zzy mFd = fd; 1653b147b770269173d5d711d6c33f142dc5e723824zzy 1663b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.INIT; 1673b147b770269173d5d711d6c33f142dc5e723824zzy 168bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly if (device == null) { 1693b147b770269173d5d711d6c33f142dc5e723824zzy // Server socket 1703b147b770269173d5d711d6c33f142dc5e723824zzy mAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); 171bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } else { 1723b147b770269173d5d711d6c33f142dc5e723824zzy // Remote socket 173bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAddress = device.getAddress(); 174bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 1753b147b770269173d5d711d6c33f142dc5e723824zzy mInputStream = new BluetoothInputStream(this); 1763b147b770269173d5d711d6c33f142dc5e723824zzy mOutputStream = new BluetoothOutputStream(this); 1773b147b770269173d5d711d6c33f142dc5e723824zzy } 1783b147b770269173d5d711d6c33f142dc5e723824zzy private BluetoothSocket(BluetoothSocket s) { 1793b147b770269173d5d711d6c33f142dc5e723824zzy mUuid = s.mUuid; 1803b147b770269173d5d711d6c33f142dc5e723824zzy mType = s.mType; 1813b147b770269173d5d711d6c33f142dc5e723824zzy mAuth = s.mAuth; 1823b147b770269173d5d711d6c33f142dc5e723824zzy mEncrypt = s.mEncrypt; 1833b147b770269173d5d711d6c33f142dc5e723824zzy mPort = s.mPort; 1840b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mInputStream = new BluetoothInputStream(this); 1850b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly mOutputStream = new BluetoothOutputStream(this); 1863b147b770269173d5d711d6c33f142dc5e723824zzy mServiceName = s.mServiceName; 1873b147b770269173d5d711d6c33f142dc5e723824zzy } 1883b147b770269173d5d711d6c33f142dc5e723824zzy private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException { 1893b147b770269173d5d711d6c33f142dc5e723824zzy BluetoothSocket as = new BluetoothSocket(this); 1903b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocketState = SocketState.CONNECTED; 1913b147b770269173d5d711d6c33f142dc5e723824zzy FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors(); 192563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "socket fd passed by stack fds: " + fds); 1933b147b770269173d5d711d6c33f142dc5e723824zzy if(fds == null || fds.length != 1) { 1943b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, "socket fd passed from stack failed, fds: " + fds); 1953b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket acept failed"); 1963b147b770269173d5d711d6c33f142dc5e723824zzy } 1973b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocket = new LocalSocket(fds[0]); 1983b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocketIS = as.mSocket.getInputStream(); 1993b147b770269173d5d711d6c33f142dc5e723824zzy as.mSocketOS = as.mSocket.getOutputStream(); 2003b147b770269173d5d711d6c33f142dc5e723824zzy as.mAddress = RemoteAddr; 2013b147b770269173d5d711d6c33f142dc5e723824zzy as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(RemoteAddr); 2023b147b770269173d5d711d6c33f142dc5e723824zzy return as; 2030b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 204bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly /** 20516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Construct a BluetoothSocket from address. Used by native code. 206bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param type type of socket 207bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param fd fd to use for connected socket, or -1 for a new socket 208bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param auth require the remote device to be authenticated 209bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param encrypt require the connection to be encrypted 210bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param address remote device that this socket can connect to 211bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @param port remote port 212bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * @throws IOException On error, for example Bluetooth not available, or 213f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * insufficient privileges 214bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly */ 215bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, 216bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly int port) throws IOException { 21716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null); 218bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 219bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly 22045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly /** @hide */ 2210b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly @Override 2220b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly protected void finalize() throws Throwable { 2230b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly try { 2240b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly close(); 2250b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } finally { 2260b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly super.finalize(); 2270b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2280b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2293b147b770269173d5d711d6c33f142dc5e723824zzy private int getSecurityFlags() { 2303b147b770269173d5d711d6c33f142dc5e723824zzy int flags = 0; 2313b147b770269173d5d711d6c33f142dc5e723824zzy if(mAuth) 2323b147b770269173d5d711d6c33f142dc5e723824zzy flags |= SEC_FLAG_AUTH; 2333b147b770269173d5d711d6c33f142dc5e723824zzy if(mEncrypt) 2343b147b770269173d5d711d6c33f142dc5e723824zzy flags |= SEC_FLAG_ENCRYPT; 2353b147b770269173d5d711d6c33f142dc5e723824zzy return flags; 2360b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2370b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2380b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 23945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * Get the remote device this socket is connecting, or connected, to. 24045e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * @return remote device 2410b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 242bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public BluetoothDevice getRemoteDevice() { 243bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mDevice; 2440b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2450b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2460b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 2470b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Get the input stream associated with this socket. 24845e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The input stream will be returned even if the socket is not yet 2490b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * connected, but operations on that stream will throw IOException until 2500b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * the associated socket is connected. 2510b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @return InputStream 2520b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 2530b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public InputStream getInputStream() throws IOException { 2540b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly return mInputStream; 2550b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2560b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 2570b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly /** 2580b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * Get the output stream associated with this socket. 25945e2704ff512d41e22af2801d76e96955469ce8dNick Pelly * <p>The output stream will be returned even if the socket is not yet 2600b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * connected, but operations on that stream will throw IOException until 2610b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * the associated socket is connected. 2620b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly * @return OutputStream 2630b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly */ 2640b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly public OutputStream getOutputStream() throws IOException { 2650b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly return mOutputStream; 2660b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly } 2670b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly 26824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** 269ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * Get the connection status of this socket, ie, whether there is an active connection with 270ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * remote device. 271ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * @return true if connected 272ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie * false if not connected 273ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie */ 274ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie public boolean isConnected() { 2753b147b770269173d5d711d6c33f142dc5e723824zzy return mSocketState == SocketState.CONNECTED; 2763b147b770269173d5d711d6c33f142dc5e723824zzy } 2773b147b770269173d5d711d6c33f142dc5e723824zzy 2783b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ void setServiceName(String name) { 2793b147b770269173d5d711d6c33f142dc5e723824zzy mServiceName = name; 2803b147b770269173d5d711d6c33f142dc5e723824zzy } 2813b147b770269173d5d711d6c33f142dc5e723824zzy 2823b147b770269173d5d711d6c33f142dc5e723824zzy /** 2833b147b770269173d5d711d6c33f142dc5e723824zzy * Attempt to connect to a remote device. 2843b147b770269173d5d711d6c33f142dc5e723824zzy * <p>This method will block until a connection is made or the connection 2853b147b770269173d5d711d6c33f142dc5e723824zzy * fails. If this method returns without an exception then this socket 2863b147b770269173d5d711d6c33f142dc5e723824zzy * is now connected. 2873b147b770269173d5d711d6c33f142dc5e723824zzy * <p>Creating new connections to 2883b147b770269173d5d711d6c33f142dc5e723824zzy * remote Bluetooth devices should not be attempted while device discovery 2893b147b770269173d5d711d6c33f142dc5e723824zzy * is in progress. Device discovery is a heavyweight procedure on the 2903b147b770269173d5d711d6c33f142dc5e723824zzy * Bluetooth adapter and will significantly slow a device connection. 2913b147b770269173d5d711d6c33f142dc5e723824zzy * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing 2923b147b770269173d5d711d6c33f142dc5e723824zzy * discovery. Discovery is not managed by the Activity, 2933b147b770269173d5d711d6c33f142dc5e723824zzy * but is run as a system service, so an application should always call 2943b147b770269173d5d711d6c33f142dc5e723824zzy * {@link BluetoothAdapter#cancelDiscovery()} even if it 2953b147b770269173d5d711d6c33f142dc5e723824zzy * did not directly request a discovery, just to be sure. 2963b147b770269173d5d711d6c33f142dc5e723824zzy * <p>{@link #close} can be used to abort this call from another thread. 2973b147b770269173d5d711d6c33f142dc5e723824zzy * @throws IOException on error, for example connection failure 2983b147b770269173d5d711d6c33f142dc5e723824zzy */ 2993b147b770269173d5d711d6c33f142dc5e723824zzy public void connect() throws IOException { 3003b147b770269173d5d711d6c33f142dc5e723824zzy if (mDevice == null) throw new IOException("Connect is called on null device"); 3013b147b770269173d5d711d6c33f142dc5e723824zzy 3023b147b770269173d5d711d6c33f142dc5e723824zzy try { 3033b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); 304903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null); 3050f42037eb7b5118015c2caca635538324ccf0ccffredc if (bluetoothProxy == null) throw new IOException("Bluetooth is off"); 3060f42037eb7b5118015c2caca635538324ccf0ccffredc mPfd = bluetoothProxy.connectSocket(mDevice, mType, 3073b147b770269173d5d711d6c33f142dc5e723824zzy mUuid, mPort, getSecurityFlags()); 3083b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 3093b147b770269173d5d711d6c33f142dc5e723824zzy { 310563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd); 3113b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed"); 3123b147b770269173d5d711d6c33f142dc5e723824zzy if (mPfd == null) throw new IOException("bt socket connect failed"); 3133b147b770269173d5d711d6c33f142dc5e723824zzy FileDescriptor fd = mPfd.getFileDescriptor(); 3143b147b770269173d5d711d6c33f142dc5e723824zzy mSocket = new LocalSocket(fd); 3153b147b770269173d5d711d6c33f142dc5e723824zzy mSocketIS = mSocket.getInputStream(); 3163b147b770269173d5d711d6c33f142dc5e723824zzy mSocketOS = mSocket.getOutputStream(); 3173b147b770269173d5d711d6c33f142dc5e723824zzy } 3183b147b770269173d5d711d6c33f142dc5e723824zzy int channel = readInt(mSocketIS); 3193b147b770269173d5d711d6c33f142dc5e723824zzy if (channel <= 0) 3203b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket connect failed"); 3213b147b770269173d5d711d6c33f142dc5e723824zzy mPort = channel; 3223b147b770269173d5d711d6c33f142dc5e723824zzy waitSocketSignal(mSocketIS); 3233b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 3243b147b770269173d5d711d6c33f142dc5e723824zzy { 3253b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) 3263b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket closed"); 3273b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.CONNECTED; 3283b147b770269173d5d711d6c33f142dc5e723824zzy } 3293b147b770269173d5d711d6c33f142dc5e723824zzy } catch (RemoteException e) { 3303b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, Log.getStackTraceString(new Throwable())); 3313b147b770269173d5d711d6c33f142dc5e723824zzy } 332ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie } 333ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie 334ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie /** 33524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * Currently returns unix errno instead of throwing IOException, 33624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * so that BluetoothAdapter can check the error code for EADDRINUSE 33724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly */ 33824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /*package*/ int bindListen() { 3393b147b770269173d5d711d6c33f142dc5e723824zzy int ret; 3403b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState == SocketState.CLOSED) return EBADFD; 341903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null); 3420f42037eb7b5118015c2caca635538324ccf0ccffredc if (bluetoothProxy == null) { 3430f42037eb7b5118015c2caca635538324ccf0ccffredc Log.e(TAG, "bindListen fail, reason: bluetooth is off"); 3440f42037eb7b5118015c2caca635538324ccf0ccffredc return -1; 3450f42037eb7b5118015c2caca635538324ccf0ccffredc } 34671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 3470f42037eb7b5118015c2caca635538324ccf0ccffredc mPfd = bluetoothProxy.createSocketChannel(mType, mServiceName, 3483b147b770269173d5d711d6c33f142dc5e723824zzy mUuid, mPort, getSecurityFlags()); 3493b147b770269173d5d711d6c33f142dc5e723824zzy } catch (RemoteException e) { 3503b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, Log.getStackTraceString(new Throwable())); 3513b147b770269173d5d711d6c33f142dc5e723824zzy return -1; 3523b147b770269173d5d711d6c33f142dc5e723824zzy } 35371c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 3543b147b770269173d5d711d6c33f142dc5e723824zzy // read out port number 35571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly try { 3563b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) { 357563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + 358563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie mPfd); 3593b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState != SocketState.INIT) return EBADFD; 3603b147b770269173d5d711d6c33f142dc5e723824zzy if(mPfd == null) return -1; 3613b147b770269173d5d711d6c33f142dc5e723824zzy FileDescriptor fd = mPfd.getFileDescriptor(); 362563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "bindListen(), new LocalSocket "); 3633b147b770269173d5d711d6c33f142dc5e723824zzy mSocket = new LocalSocket(fd); 364563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() "); 3653b147b770269173d5d711d6c33f142dc5e723824zzy mSocketIS = mSocket.getInputStream(); 3663b147b770269173d5d711d6c33f142dc5e723824zzy mSocketOS = mSocket.getOutputStream(); 3673b147b770269173d5d711d6c33f142dc5e723824zzy } 368563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS); 3693b147b770269173d5d711d6c33f142dc5e723824zzy int channel = readInt(mSocketIS); 3703b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) { 3713b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState == SocketState.INIT) 3723b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.LISTENING; 3733b147b770269173d5d711d6c33f142dc5e723824zzy } 374563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "channel: " + channel); 3753b147b770269173d5d711d6c33f142dc5e723824zzy if (mPort == -1) { 3763b147b770269173d5d711d6c33f142dc5e723824zzy mPort = channel; 3773b147b770269173d5d711d6c33f142dc5e723824zzy } // else ASSERT(mPort == channel) 3783b147b770269173d5d711d6c33f142dc5e723824zzy ret = 0; 3793b147b770269173d5d711d6c33f142dc5e723824zzy } catch (IOException e) { 3803b147b770269173d5d711d6c33f142dc5e723824zzy Log.e(TAG, "bindListen, fail to get port number, exception: " + e); 3813b147b770269173d5d711d6c33f142dc5e723824zzy return -1; 3823b147b770269173d5d711d6c33f142dc5e723824zzy } 3833b147b770269173d5d711d6c33f142dc5e723824zzy return ret; 3843b147b770269173d5d711d6c33f142dc5e723824zzy } 385ceb6c9f517ede73bfb677e55fda9d9db6089ae69Matthew Xie 3863b147b770269173d5d711d6c33f142dc5e723824zzy /*package*/ BluetoothSocket accept(int timeout) throws IOException { 3873b147b770269173d5d711d6c33f142dc5e723824zzy BluetoothSocket acceptedSocket; 3883b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState != SocketState.LISTENING) throw new IOException("bt socket is not in listen state"); 389652678af4d18b9a6c18ce6a860de01d958bc82fezzy if(timeout > 0) { 390652678af4d18b9a6c18ce6a860de01d958bc82fezzy Log.d(TAG, "accept() set timeout (ms):" + timeout); 391652678af4d18b9a6c18ce6a860de01d958bc82fezzy mSocket.setSoTimeout(timeout); 392652678af4d18b9a6c18ce6a860de01d958bc82fezzy } 3933b147b770269173d5d711d6c33f142dc5e723824zzy String RemoteAddr = waitSocketSignal(mSocketIS); 394652678af4d18b9a6c18ce6a860de01d958bc82fezzy if(timeout > 0) 395652678af4d18b9a6c18ce6a860de01d958bc82fezzy mSocket.setSoTimeout(0); 3963b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 3973b147b770269173d5d711d6c33f142dc5e723824zzy { 3983b147b770269173d5d711d6c33f142dc5e723824zzy if (mSocketState != SocketState.LISTENING) 3993b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket is not in listen state"); 4003b147b770269173d5d711d6c33f142dc5e723824zzy acceptedSocket = acceptSocket(RemoteAddr); 4013b147b770269173d5d711d6c33f142dc5e723824zzy //quick drop the reference of the file handle 40271c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 4033b147b770269173d5d711d6c33f142dc5e723824zzy return acceptedSocket; 40471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 40571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 40671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int available() throws IOException { 407563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "available: " + mSocketIS); 4083b147b770269173d5d711d6c33f142dc5e723824zzy return mSocketIS.available(); 40971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 41071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 41171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int read(byte[] b, int offset, int length) throws IOException { 4123b147b770269173d5d711d6c33f142dc5e723824zzy 413563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length); 4143b147b770269173d5d711d6c33f142dc5e723824zzy int ret = mSocketIS.read(b, offset, length); 4153b147b770269173d5d711d6c33f142dc5e723824zzy if(ret < 0) 4163b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("bt socket closed, read return: " + ret); 417563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret); 4183b147b770269173d5d711d6c33f142dc5e723824zzy return ret; 41971c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 42071c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 42171c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly /*package*/ int write(byte[] b, int offset, int length) throws IOException { 4223b147b770269173d5d711d6c33f142dc5e723824zzy 423563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length); 4243b147b770269173d5d711d6c33f142dc5e723824zzy mSocketOS.write(b, offset, length); 4253b147b770269173d5d711d6c33f142dc5e723824zzy // There is no good way to confirm since the entire process is asynchronous anyway 426563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length); 4273b147b770269173d5d711d6c33f142dc5e723824zzy return length; 4283b147b770269173d5d711d6c33f142dc5e723824zzy } 4293b147b770269173d5d711d6c33f142dc5e723824zzy 4303b147b770269173d5d711d6c33f142dc5e723824zzy @Override 4313b147b770269173d5d711d6c33f142dc5e723824zzy public void close() throws IOException { 432d77982ef29b2d3b5de42846ba308fc9f880938a2Matthew Xie if (VDBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState); 4333b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState == SocketState.CLOSED) 4343b147b770269173d5d711d6c33f142dc5e723824zzy return; 4353b147b770269173d5d711d6c33f142dc5e723824zzy else 4363b147b770269173d5d711d6c33f142dc5e723824zzy { 4373b147b770269173d5d711d6c33f142dc5e723824zzy synchronized(this) 4383b147b770269173d5d711d6c33f142dc5e723824zzy { 4393b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocketState == SocketState.CLOSED) 4403b147b770269173d5d711d6c33f142dc5e723824zzy return; 4413b147b770269173d5d711d6c33f142dc5e723824zzy mSocketState = SocketState.CLOSED; 442563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS + 4433b147b770269173d5d711d6c33f142dc5e723824zzy ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket); 4443b147b770269173d5d711d6c33f142dc5e723824zzy if(mSocket != null) { 445563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "Closing mSocket: " + mSocket); 4463b147b770269173d5d711d6c33f142dc5e723824zzy mSocket.shutdownInput(); 4473b147b770269173d5d711d6c33f142dc5e723824zzy mSocket.shutdownOutput(); 4483b147b770269173d5d711d6c33f142dc5e723824zzy mSocket.close(); 4493b147b770269173d5d711d6c33f142dc5e723824zzy mSocket = null; 4503b147b770269173d5d711d6c33f142dc5e723824zzy } 4513b147b770269173d5d711d6c33f142dc5e723824zzy if(mPfd != null) 4523b147b770269173d5d711d6c33f142dc5e723824zzy mPfd.detachFd(); 4533b147b770269173d5d711d6c33f142dc5e723824zzy } 45471c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 45571c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly } 45671c3c7806acb2b2b7b8441817c26a2101d447bbeNick Pelly 4573b147b770269173d5d711d6c33f142dc5e723824zzy /*package */ void removeChannel() { 4583b147b770269173d5d711d6c33f142dc5e723824zzy } 45916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 4603b147b770269173d5d711d6c33f142dc5e723824zzy /*package */ int getPort() { 4613b147b770269173d5d711d6c33f142dc5e723824zzy return mPort; 4623b147b770269173d5d711d6c33f142dc5e723824zzy } 4633b147b770269173d5d711d6c33f142dc5e723824zzy private String convertAddr(final byte[] addr) { 4643b147b770269173d5d711d6c33f142dc5e723824zzy return String.format("%02X:%02X:%02X:%02X:%02X:%02X", 4653b147b770269173d5d711d6c33f142dc5e723824zzy addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]); 4663b147b770269173d5d711d6c33f142dc5e723824zzy } 4673b147b770269173d5d711d6c33f142dc5e723824zzy private String waitSocketSignal(InputStream is) throws IOException { 4683b147b770269173d5d711d6c33f142dc5e723824zzy byte [] sig = new byte[SOCK_SIGNAL_SIZE]; 4693b147b770269173d5d711d6c33f142dc5e723824zzy int ret = readAll(is, sig); 470563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "waitSocketSignal read 16 bytes signal ret: " + ret); 4713b147b770269173d5d711d6c33f142dc5e723824zzy ByteBuffer bb = ByteBuffer.wrap(sig); 4723b147b770269173d5d711d6c33f142dc5e723824zzy bb.order(ByteOrder.nativeOrder()); 4733b147b770269173d5d711d6c33f142dc5e723824zzy int size = bb.getShort(); 474652678af4d18b9a6c18ce6a860de01d958bc82fezzy if(size != SOCK_SIGNAL_SIZE) 475652678af4d18b9a6c18ce6a860de01d958bc82fezzy throw new IOException("Connection failure, wrong signal size: " + size); 4763b147b770269173d5d711d6c33f142dc5e723824zzy byte [] addr = new byte[6]; 4773b147b770269173d5d711d6c33f142dc5e723824zzy bb.get(addr); 4783b147b770269173d5d711d6c33f142dc5e723824zzy int channel = bb.getInt(); 4793b147b770269173d5d711d6c33f142dc5e723824zzy int status = bb.getInt(); 4803b147b770269173d5d711d6c33f142dc5e723824zzy String RemoteAddr = convertAddr(addr); 481563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: " 4823b147b770269173d5d711d6c33f142dc5e723824zzy + RemoteAddr + ", channel: " + channel + ", status: " + status); 4833b147b770269173d5d711d6c33f142dc5e723824zzy if(status != 0) 4843b147b770269173d5d711d6c33f142dc5e723824zzy throw new IOException("Connection failure, status: " + status); 4853b147b770269173d5d711d6c33f142dc5e723824zzy return RemoteAddr; 4863b147b770269173d5d711d6c33f142dc5e723824zzy } 4873b147b770269173d5d711d6c33f142dc5e723824zzy private int readAll(InputStream is, byte[] b) throws IOException { 4883b147b770269173d5d711d6c33f142dc5e723824zzy int left = b.length; 4893b147b770269173d5d711d6c33f142dc5e723824zzy while(left > 0) { 4903b147b770269173d5d711d6c33f142dc5e723824zzy int ret = is.read(b, b.length - left, left); 491d6883533e4ac3f73d2fde1db9a1dddf06dac6709fredc if(ret <= 0) 492652678af4d18b9a6c18ce6a860de01d958bc82fezzy throw new IOException("read failed, socket might closed or timeout, read ret: " + ret); 4933b147b770269173d5d711d6c33f142dc5e723824zzy left -= ret; 4943b147b770269173d5d711d6c33f142dc5e723824zzy if(left != 0) 4953b147b770269173d5d711d6c33f142dc5e723824zzy Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) + 4963b147b770269173d5d711d6c33f142dc5e723824zzy ", expect size: " + b.length); 49716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 4983b147b770269173d5d711d6c33f142dc5e723824zzy return b.length; 4993b147b770269173d5d711d6c33f142dc5e723824zzy } 5003b147b770269173d5d711d6c33f142dc5e723824zzy 5013b147b770269173d5d711d6c33f142dc5e723824zzy private int readInt(InputStream is) throws IOException { 5023b147b770269173d5d711d6c33f142dc5e723824zzy byte[] ibytes = new byte[4]; 5033b147b770269173d5d711d6c33f142dc5e723824zzy int ret = readAll(is, ibytes); 504563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret); 5053b147b770269173d5d711d6c33f142dc5e723824zzy ByteBuffer bb = ByteBuffer.wrap(ibytes); 5063b147b770269173d5d711d6c33f142dc5e723824zzy bb.order(ByteOrder.nativeOrder()); 5073b147b770269173d5d711d6c33f142dc5e723824zzy return bb.getInt(); 50816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 5090b6955a48bad9aee01ae2f0c06d3f168ca603ab7Nick Pelly} 510