Home | History | Annotate | Download | only in bluetooth
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.bluetooth;
     18 
     19 import android.annotation.UnsupportedAppUsage;
     20 import android.os.Handler;
     21 import android.os.ParcelUuid;
     22 import android.util.Log;
     23 
     24 import java.io.Closeable;
     25 import java.io.IOException;
     26 
     27 /**
     28  * A listening Bluetooth socket.
     29  *
     30  * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
     31  * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
     32  * side, use a {@link BluetoothServerSocket} to create a listening server
     33  * socket. When a connection is accepted by the {@link BluetoothServerSocket},
     34  * it will return a new {@link BluetoothSocket} to manage the connection.
     35  * On the client side, use a single {@link BluetoothSocket} to both initiate
     36  * an outgoing connection and to manage the connection.
     37  *
     38  * <p>For Bluetooth BR/EDR, the most common type of socket is RFCOMM, which is the type supported by
     39  * the Android APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth BR/EDR. It
     40  * is also known as the Serial Port Profile (SPP). To create a listening
     41  * {@link BluetoothServerSocket} that's ready for incoming Bluetooth BR/EDR connections, use {@link
     42  * BluetoothAdapter#listenUsingRfcommWithServiceRecord
     43  * BluetoothAdapter.listenUsingRfcommWithServiceRecord()}.
     44  *
     45  * <p>For Bluetooth LE, the socket uses LE Connection-oriented Channel (CoC). LE CoC is a
     46  * connection-oriented, streaming transport over Bluetooth LE and has a credit-based flow control.
     47  * Correspondingly, use {@link BluetoothAdapter#listenUsingL2capChannel
     48  * BluetoothAdapter.listenUsingL2capChannel()} to create a listening {@link BluetoothServerSocket}
     49  * that's ready for incoming Bluetooth LE CoC connections. For LE CoC, you can use {@link #getPsm()}
     50  * to get the protocol/service multiplexer (PSM) value that the peer needs to use to connect to your
     51  * socket.
     52  *
     53  * <p> After the listening {@link BluetoothServerSocket} is created, call {@link #accept()} to
     54  * listen for incoming connection requests. This call will block until a connection is established,
     55  * at which point, it will return a {@link BluetoothSocket} to manage the connection. Once the
     56  * {@link BluetoothSocket} is acquired, it's a good idea to call {@link #close()} on the {@link
     57  * BluetoothServerSocket} when it's no longer needed for accepting
     58  * connections. Closing the {@link BluetoothServerSocket} will <em>not</em> close the returned
     59  * {@link BluetoothSocket}.
     60  *
     61  * <p>{@link BluetoothServerSocket} is thread
     62  * safe. In particular, {@link #close} will always immediately abort ongoing
     63  * operations and close the server socket.
     64  *
     65  * <p class="note"><strong>Note:</strong>
     66  * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
     67  *
     68  * <div class="special reference">
     69  * <h3>Developer Guides</h3>
     70  * <p>For more information about using Bluetooth, read the
     71  * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
     72  * </div>
     73  *
     74  * {@see BluetoothSocket}
     75  */
     76 public final class BluetoothServerSocket implements Closeable {
     77 
     78     private static final String TAG = "BluetoothServerSocket";
     79     private static final boolean DBG = false;
     80     @UnsupportedAppUsage
     81     /*package*/ final BluetoothSocket mSocket;
     82     private Handler mHandler;
     83     private int mMessage;
     84     private int mChannel;
     85 
     86     /**
     87      * Construct a socket for incoming connections.
     88      *
     89      * @param type type of socket
     90      * @param auth require the remote device to be authenticated
     91      * @param encrypt require the connection to be encrypted
     92      * @param port remote port
     93      * @throws IOException On error, for example Bluetooth not available, or insufficient
     94      * privileges
     95      */
     96     /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
     97             throws IOException {
     98         mChannel = port;
     99         mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null);
    100         if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
    101             mSocket.setExcludeSdp(true);
    102         }
    103     }
    104 
    105     /**
    106      * Construct a socket for incoming connections.
    107      *
    108      * @param type type of socket
    109      * @param auth require the remote device to be authenticated
    110      * @param encrypt require the connection to be encrypted
    111      * @param port remote port
    112      * @param mitm enforce man-in-the-middle protection for authentication.
    113      * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
    114      * @throws IOException On error, for example Bluetooth not available, or insufficient
    115      * privileges
    116      */
    117     /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port,
    118             boolean mitm, boolean min16DigitPin)
    119             throws IOException {
    120         mChannel = port;
    121         mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null, mitm,
    122                 min16DigitPin);
    123         if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
    124             mSocket.setExcludeSdp(true);
    125         }
    126     }
    127 
    128     /**
    129      * Construct a socket for incoming connections.
    130      *
    131      * @param type type of socket
    132      * @param auth require the remote device to be authenticated
    133      * @param encrypt require the connection to be encrypted
    134      * @param uuid uuid
    135      * @throws IOException On error, for example Bluetooth not available, or insufficient
    136      * privileges
    137      */
    138     /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, ParcelUuid uuid)
    139             throws IOException {
    140         mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, -1, uuid);
    141         // TODO: This is the same as mChannel = -1 - is this intentional?
    142         mChannel = mSocket.getPort();
    143     }
    144 
    145 
    146     /**
    147      * Block until a connection is established.
    148      * <p>Returns a connected {@link BluetoothSocket} on successful connection.
    149      * <p>Once this call returns, it can be called again to accept subsequent
    150      * incoming connections.
    151      * <p>{@link #close} can be used to abort this call from another thread.
    152      *
    153      * @return a connected {@link BluetoothSocket}
    154      * @throws IOException on error, for example this call was aborted, or timeout
    155      */
    156     public BluetoothSocket accept() throws IOException {
    157         return accept(-1);
    158     }
    159 
    160     /**
    161      * Block until a connection is established, with timeout.
    162      * <p>Returns a connected {@link BluetoothSocket} on successful connection.
    163      * <p>Once this call returns, it can be called again to accept subsequent
    164      * incoming connections.
    165      * <p>{@link #close} can be used to abort this call from another thread.
    166      *
    167      * @return a connected {@link BluetoothSocket}
    168      * @throws IOException on error, for example this call was aborted, or timeout
    169      */
    170     public BluetoothSocket accept(int timeout) throws IOException {
    171         return mSocket.accept(timeout);
    172     }
    173 
    174     /**
    175      * Immediately close this socket, and release all associated resources.
    176      * <p>Causes blocked calls on this socket in other threads to immediately
    177      * throw an IOException.
    178      * <p>Closing the {@link BluetoothServerSocket} will <em>not</em>
    179      * close any {@link BluetoothSocket} received from {@link #accept()}.
    180      */
    181     public void close() throws IOException {
    182         if (DBG) Log.d(TAG, "BluetoothServerSocket:close() called. mChannel=" + mChannel);
    183         synchronized (this) {
    184             if (mHandler != null) {
    185                 mHandler.obtainMessage(mMessage).sendToTarget();
    186             }
    187         }
    188         mSocket.close();
    189     }
    190 
    191     /*package*/
    192     synchronized void setCloseHandler(Handler handler, int message) {
    193         mHandler = handler;
    194         mMessage = message;
    195     }
    196 
    197     /*package*/ void setServiceName(String serviceName) {
    198         mSocket.setServiceName(serviceName);
    199     }
    200 
    201     /**
    202      * Returns the channel on which this socket is bound.
    203      *
    204      * @hide
    205      */
    206     public int getChannel() {
    207         return mChannel;
    208     }
    209 
    210     /**
    211      * Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
    212      * Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
    213      * {@link BluetoothAdapter#listenUsingL2capChannel()} or {@link
    214      * BluetoothAdapter#listenUsingInsecureL2capChannel()}. The returned value is undefined if this
    215      * method is called on non-L2CAP server sockets.
    216      *
    217      * @return the assigned PSM or LE_PSM value depending on transport
    218      */
    219     public int getPsm() {
    220         return mChannel;
    221     }
    222 
    223     /**
    224      * Sets the channel on which future sockets are bound.
    225      * Currently used only when a channel is auto generated.
    226      */
    227     /*package*/ void setChannel(int newChannel) {
    228         /* TODO: From a design/architecture perspective this is wrong.
    229          *       The bind operation should be conducted through this class
    230          *       and the resulting port should be kept in mChannel, and
    231          *       not set from BluetoothAdapter. */
    232         if (mSocket != null) {
    233             if (mSocket.getPort() != newChannel) {
    234                 Log.w(TAG, "The port set is different that the underlying port. mSocket.getPort(): "
    235                         + mSocket.getPort() + " requested newChannel: " + newChannel);
    236             }
    237         }
    238         mChannel = newChannel;
    239     }
    240 
    241     @Override
    242     public String toString() {
    243         StringBuilder sb = new StringBuilder();
    244         sb.append("ServerSocket: Type: ");
    245         switch (mSocket.getConnectionType()) {
    246             case BluetoothSocket.TYPE_RFCOMM: {
    247                 sb.append("TYPE_RFCOMM");
    248                 break;
    249             }
    250             case BluetoothSocket.TYPE_L2CAP: {
    251                 sb.append("TYPE_L2CAP");
    252                 break;
    253             }
    254             case BluetoothSocket.TYPE_L2CAP_LE: {
    255                 sb.append("TYPE_L2CAP_LE");
    256                 break;
    257             }
    258             case BluetoothSocket.TYPE_SCO: {
    259                 sb.append("TYPE_SCO");
    260                 break;
    261             }
    262         }
    263         sb.append(" Channel: ").append(mChannel);
    264         return sb.toString();
    265     }
    266 }
    267