1bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde/* 2bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* Copyright (C) 2015 Samsung System LSI 3bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* Licensed under the Apache License, Version 2.0 (the "License"); 4bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* you may not use this file except in compliance with the License. 5bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* You may obtain a copy of the License at 6bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* 7bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* http://www.apache.org/licenses/LICENSE-2.0 8bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* 9bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* Unless required by applicable law or agreed to in writing, software 10bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* distributed under the License is distributed on an "AS IS" BASIS, 11bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* See the License for the specific language governing permissions and 13bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* limitations under the License. 14bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde*/ 15bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondepackage com.android.bluetooth; 16bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 17bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport java.io.IOException; 18bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport java.util.concurrent.CountDownLatch; 19bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 20bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport javax.obex.ObexSession; 21bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport javax.obex.ResponseCodes; 22bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport javax.obex.ServerSession; 23bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 24bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.bluetooth.BluetoothAdapter; 25bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.bluetooth.BluetoothDevice; 26bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.bluetooth.BluetoothServerSocket; 27bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.bluetooth.BluetoothSocket; 28bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.util.Log; 29bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 30bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde/** 31bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Wraps multiple BluetoothServerSocket objects to make it possible to accept connections on 32bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * both a RFCOMM and L2CAP channel in parallel.<br> 33bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Create an instance using {@link #create()}, which will block until the sockets have been created 34bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * and channel numbers have been assigned.<br> 35bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Use {@link #getRfcommChannel()} and {@link #getL2capPsm()} to get the channel numbers to 36bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * put into the SDP record.<br> 37bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Call {@link #shutdown(boolean)} to terminate the accept threads created by the call to 38bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * {@link #create(IObexConnectionHandler)}.<br> 39bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * A reference to an object of this type cannot be reused, and the {@link BluetoothServerSocket} 40bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * object references passed to this object will be closed by this object, hence cannot be reused 41bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * either (This is needed, as the only way to interrupt an accept call is to close the socket...) 42bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * <br> 43bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * When a connection is accepted, 44bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * {@link IObexConnectionHandler#onConnect(BluetoothDevice, BluetoothSocket)} will be called.<br> 45bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * If the an error occur while waiting for an incoming connection 46bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * {@link IObexConnectionHandler#onConnect(BluetoothDevice, BluetoothSocket)} will be called.<br> 47bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * In both cases the {@link ObexServerSockets} object have terminated, and a new must be created. 48bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 49bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondepublic class ObexServerSockets { 50bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private final String TAG; 51bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private static final String STAG = "ObexServerSockets"; 52bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private static final boolean D = true; // TODO: set to false! 53bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private static final int NUMBER_OF_SOCKET_TYPES = 2; // increment if LE will be supported 54bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 55bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private final IObexConnectionHandler mConHandler; 56bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /* The wrapped sockets */ 57bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private final BluetoothServerSocket mRfcommSocket; 58bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private final BluetoothServerSocket mL2capSocket; 59bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /* Handles to the accept threads. Needed for shutdown. */ 60bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private SocketAcceptThread mRfcommThread = null; 61bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private SocketAcceptThread mL2capThread = null; 62bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 63bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private volatile boolean mConAccepted = false; 64bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 65bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private static volatile int sInstanceCounter = 0; 66bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 67bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private ObexServerSockets(IObexConnectionHandler conHandler, 68bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde BluetoothServerSocket rfcommSocket, 69bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde BluetoothServerSocket l2capSocket) { 70bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mConHandler = conHandler; 71bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mRfcommSocket = rfcommSocket; 72bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mL2capSocket = l2capSocket; 73bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde TAG = "ObexServerSockets" + sInstanceCounter++; 74bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 75bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 76bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 77bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Creates an RFCOMM {@link BluetoothServerSocket} and a L2CAP {@link BluetoothServerSocket} 78bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @param validator a reference to the {@link IObexConnectionHandler} object to call 79bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * to validate an incoming connection. 80bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @return a reference to a {@link ObexServerSockets} object instance. 81bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @throws IOException if it occurs while creating the {@link BluetoothServerSocket}s. 82bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 83bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde public static ObexServerSockets create(IObexConnectionHandler validator) { 84bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde return create(validator, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, 85bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP); 86bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 87bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 88bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 89bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Creates an RFCOMM {@link BluetoothServerSocket} and a L2CAP {@link BluetoothServerSocket} 90bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * with specific l2cap and RFCOMM channel numbers. It is the responsibility of the caller to 91bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * ensure the numbers are free and can be used, e.g. by calling {@link #getL2capPsm()} and 92bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * {@link #getRfcommChannel()} in {@link ObexServerSockets}. 93bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @param validator a reference to the {@link IObexConnectionHandler} object to call 94bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * to validate an incoming connection. 95bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @return a reference to a {@link ObexServerSockets} object instance. 96bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @throws IOException if it occurs while creating the {@link BluetoothServerSocket}s. 97bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * 98bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * TODO: Make public when it becomes possible to determine that the listen-call 99bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * failed due to channel-in-use. 100bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 101bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private static ObexServerSockets create(IObexConnectionHandler validator, 102bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde int rfcommChannel, int l2capPsm) { 103bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(D) Log.d(STAG,"create(rfcomm = " +rfcommChannel + ", l2capPsm = " + l2capPsm +")"); 104bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); 105bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(bt == null) { 106bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde throw new RuntimeException("No bluetooth adapter..."); 107bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 108bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde BluetoothServerSocket rfcommSocket = null; 109bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde BluetoothServerSocket l2capSocket = null; 110bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde boolean initSocketOK = false; 111bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde final int CREATE_RETRY_TIME = 10; 112bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 113bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // It's possible that create will fail in some cases. retry for 10 times 114bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde for (int i = 0; i < CREATE_RETRY_TIME; i++) { 115bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde initSocketOK = true; 116bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde try { 117bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(rfcommSocket == null) { 118bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde rfcommSocket = bt.listenUsingRfcommOn(rfcommChannel); 119bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 120bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(l2capSocket == null) { 121bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde l2capSocket = bt.listenUsingL2capOn(l2capPsm); 122bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 123bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } catch (IOException e) { 124bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.e(STAG, "Error create ServerSockets ",e); 125bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde initSocketOK = false; 126bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 127bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if (!initSocketOK) { 128bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // Need to break out of this loop if BT is being turned off. 129bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde int state = bt.getState(); 130bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if ((state != BluetoothAdapter.STATE_TURNING_ON) && 131bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde (state != BluetoothAdapter.STATE_ON)) { 132bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.w(STAG, "initServerSockets failed as BT is (being) turned off"); 133bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde break; 134bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 135bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde try { 136bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if (D) Log.v(STAG, "waiting 300 ms..."); 137bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Thread.sleep(300); 138bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } catch (InterruptedException e) { 139bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.e(STAG, "create() was interrupted"); 140bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 141bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } else { 142bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde break; 143bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 144bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 145bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 146bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if (initSocketOK) { 147bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if (D) Log.d(STAG, "Succeed to create listening sockets "); 148bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde ObexServerSockets sockets = new ObexServerSockets(validator, rfcommSocket, l2capSocket); 149bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde sockets.startAccept(); 150bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde return sockets; 151bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } else { 152bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.e(STAG, "Error to create listening socket after " + CREATE_RETRY_TIME + " try"); 153bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde return null; 154bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 155bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 156bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 157bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 158bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Returns the channel number assigned to the RFCOMM socket. This will be a static value, that 159bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * should be reused for multiple connections. 160bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @return the RFCOMM channel number 161bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 162bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde public int getRfcommChannel() { 163bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde return mRfcommSocket.getChannel(); 164bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 165bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 166bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 167bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Returns the channel number assigned to the L2CAP socket. This will be a static value, that 168bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * should be reused for multiple connections. 169bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @return the L2CAP channel number 170bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 171bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde public int getL2capPsm() { 172bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde return mL2capSocket.getChannel(); 173bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 174bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 175bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 176bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Initiate the accept threads. 177bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Will create a thread for each socket type. an incoming connection will be signaled to 178bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * the {@link IObexConnectionValidator#onConnect()}, at which point both threads will exit. 179bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 180bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private void startAccept() { 181bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(D) Log.d(TAG,"startAccept()"); 182bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde prepareForNewConnect(); 183bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 184bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mRfcommThread = new SocketAcceptThread(mRfcommSocket); 185bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mRfcommThread.start(); 186bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 187bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mL2capThread = new SocketAcceptThread(mL2capSocket); 188bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mL2capThread.start(); 189bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 190bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 191bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 192bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Set state to accept new incoming connection. Will cause the next incoming connection to be 193bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Signaled through {@link IObexConnectionValidator#onConnect()}; 194bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 195bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde public void prepareForNewConnect() { 196bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(D) Log.d(TAG, "prepareForNewConnect()"); 197bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mConAccepted = false; 198bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 199bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 200bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 201bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Called from the AcceptThreads to signal an incoming connection. 202bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * This is the entry point that needs to synchronize between the accept 203bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * threads, and ensure only a single connection is accepted. 204bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * {@link mAcceptedSocket} is used a state variable. 205bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @param device the connecting device. 206bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @param conSocket the socket associated with the connection. 207bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @return true if the connection is accepted, false otherwise. 208bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 209bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde synchronized private boolean onConnect(BluetoothDevice device, BluetoothSocket conSocket) { 210bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(D) Log.d(TAG, "onConnect() socket: " + conSocket + " mConAccepted = " + mConAccepted); 211bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(mConAccepted == false && mConHandler.onConnect(device, conSocket) == true) { 212bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mConAccepted = true; // TODO: Reset this when ready to accept new connection 213bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /* Signal the remaining threads to stop. 214bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde shutdown(false); */ // UPDATE: TODO: remove - redesigned to keep running... 215bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde return true; 216bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 217bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde return false; 218bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 219bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 220bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 221bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Signal to the {@link IObexConnectionHandler} that an error have occurred. 222bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 223bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde synchronized private void onAcceptFailed() { 224bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.w(TAG,"onAcceptFailed() calling shutdown..."); 225bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mConHandler.onAcceptFailed(); 226bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde shutdown(false); 227bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 228bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 229bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 230bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Terminate any running accept threads 231bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @param block Set true to block the calling thread until the AcceptThreads 232bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * has ended execution 233bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 234bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde synchronized public void shutdown(boolean block) { 235bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(D) Log.d(TAG, "shutdown(block = " + block + ")"); 236bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(mRfcommThread != null) { 237bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mRfcommThread.shutdown(); 238bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 239bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(mL2capThread != null){ 240bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mL2capThread.shutdown(); 241bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 242bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(block == true) { 243bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde while(mRfcommThread != null || mL2capThread != null) { 244bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde try { 245bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(mRfcommThread != null) { 246bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mRfcommThread.join(); 247bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mRfcommThread = null; 248bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 249bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(mL2capThread != null) { 250bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mL2capThread.join(); 251bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mL2capThread = null; 252bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 253bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } catch (InterruptedException e) { 254bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.i(TAG, "shutdown() interrupted, continue waiting...", e); 255bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 256bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 257bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } else { 258bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mRfcommThread = null; 259bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mL2capThread = null; 260bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 261bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 262bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 263bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 264bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * A thread that runs in the background waiting for remote an incoming 265bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * connect. Once a remote socket connects, this thread will be 266bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * shutdown. When the remote disconnect, this thread shall be restarted to 267bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * accept a new connection. 268bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 269bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private class SocketAcceptThread extends Thread { 270bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 271bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private boolean mStopped = false; 272bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde private final BluetoothServerSocket mServerSocket; 273bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 274bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 275bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Create a SocketAcceptThread 276bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @param serverSocket shall never be null. 277bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @param latch shall never be null. 278bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * @throws IllegalArgumentException 279bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 280bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde public SocketAcceptThread(BluetoothServerSocket serverSocket) { 281bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(serverSocket == null) { 282bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde throw new IllegalArgumentException("serverSocket cannot be null"); 283bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 284bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mServerSocket = serverSocket; 285bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 286bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 287bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 288bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Run until shutdown of BT. 289bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Accept incoming connections and reject if needed. Keep accepting incoming connections. 290bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 291bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde @Override 292bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde public void run() { 293bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde try { 294bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde while (!mStopped) { 295bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde BluetoothSocket connSocket; 296bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde BluetoothDevice device; 297bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 298bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde try { 299bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if (D) Log.d(TAG, "Accepting socket connection..."); 300bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 301bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde connSocket = mServerSocket.accept(); 302bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if (D) Log.d(TAG, "Accepted socket connection from: " + mServerSocket); 303bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 304bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if (connSocket == null) { 305bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // TODO: Do we need a max error count, to avoid spinning? 306bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.w(TAG, "connSocket is null - reattempt accept"); 307bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde continue; 308bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 309bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde device = connSocket.getRemoteDevice(); 310bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 311bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if (device == null) { 312bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.i(TAG, "getRemoteDevice() = null - reattempt accept"); 313bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde try{ 314bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde connSocket.close(); 315bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } catch (IOException e) { 316bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.w(TAG, "Error closing the socket. ignoring...",e ); 317bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 318bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde continue; 319bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 320bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 321bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /* Signal to the service that we have received an incoming connection. 322bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 323bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde boolean isValid = ObexServerSockets.this.onConnect(device, connSocket); 324bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 325bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(isValid == false) { 326bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /* Close connection if we already have a connection with another device 327bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * by responding to the OBEX connect request. 328bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 329bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.i(TAG, "RemoteDevice is invalid - creating ObexRejectServer."); 330bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde BluetoothObexTransport obexTrans = 331bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde new BluetoothObexTransport(connSocket); 332bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // Create and detach a selfdestructing ServerSession to respond to any 333bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // incoming OBEX signals. 334bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde new ServerSession(obexTrans, 335bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde new ObexRejectServer( 336bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde ResponseCodes.OBEX_HTTP_UNAVAILABLE, 337bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde connSocket), 338bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde null); 339bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // now wait for a new connect 340bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } else { 341bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // now wait for a new connect 342bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 343bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } catch (IOException ex) { 344bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(mStopped == true) { 345bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // Expected exception because of shutdown. 346bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } else { 347bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde Log.w(TAG, "Accept exception for " + 348bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mServerSocket, ex); 349bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde ObexServerSockets.this.onAcceptFailed(); 350bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 351bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mStopped=true; 352bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 353bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } // End while() 354bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } finally { 355bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if (D) Log.d(TAG, "AcceptThread ended for: " + mServerSocket); 356bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 357bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 358bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 359bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde /** 360bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Shuts down the accept threads, and closes the ServerSockets, causing all related 361bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * BluetoothSockets to disconnect, hence do not call until all all accepted connections 362bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * are ready to be disconnected. 363bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */ 364bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde public void shutdown() { 365bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(mStopped == false) { 366bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mStopped = true; 367bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // TODO: According to the documentation, this should not close the accepted 368bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // sockets - and that is true, but it closes the l2cap connections, and 369bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // therefore it implicitly also closes the accepted sockets... 370bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde try { 371bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde mServerSocket.close(); 372bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } catch (IOException e) { 373bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(D) Log.d(TAG, "Exception while thread shutdown:", e); 374bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 375bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 376bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // If called from another thread, interrupt the thread 377bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(!Thread.currentThread().equals(this)){ 378bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // TODO: Will this interrupt the thread if it is blocked in synchronized? 379bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde // Else: change to use InterruptableLock 380bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde if(D) Log.d(TAG, "shutdown called from another thread - interrupt()."); 381bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde interrupt(); 382bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 383bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 384bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde } 385bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde 386bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde} 387