1/* 2 * Copyright (c) 2008-2009, Motorola, Inc. 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * - Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * - Neither the name of the Motorola, Inc. nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33package com.android.bluetooth.opp; 34 35import java.io.IOException; 36import java.net.ServerSocket; 37import java.net.Socket; 38 39import android.bluetooth.BluetoothAdapter; 40import android.bluetooth.BluetoothServerSocket; 41import android.bluetooth.BluetoothSocket; 42import android.bluetooth.BluetoothUuid; 43import android.os.Handler; 44import android.os.Message; 45import android.util.Log; 46 47/** 48 * This class listens on OPUSH channel for incoming connection 49 */ 50public class BluetoothOppRfcommListener { 51 private static final String TAG = "BtOppRfcommListener"; 52 53 private static final boolean V = Constants.VERBOSE; 54 55 public static final int MSG_INCOMING_BTOPP_CONNECTION = 100; 56 57 private volatile boolean mInterrupted; 58 59 private Thread mSocketAcceptThread; 60 61 private Handler mCallback; 62 63 private static final int CREATE_RETRY_TIME = 10; 64 65 private final BluetoothAdapter mAdapter; 66 67 private BluetoothServerSocket mBtServerSocket = null; 68 69 private ServerSocket mTcpServerSocket = null; 70 71 public BluetoothOppRfcommListener(BluetoothAdapter adapter) { 72 mAdapter = adapter; 73 } 74 75 76 public synchronized boolean start(Handler callback) { 77 if (mSocketAcceptThread == null) { 78 mCallback = callback; 79 80 mSocketAcceptThread = new Thread(TAG) { 81 82 public void run() { 83 if (Constants.USE_TCP_DEBUG) { 84 try { 85 if (V) Log.v(TAG, "Create TCP ServerSocket"); 86 mTcpServerSocket = new ServerSocket(Constants.TCP_DEBUG_PORT, 1); 87 } catch (IOException e) { 88 Log.e(TAG, "Error listing on port" + Constants.TCP_DEBUG_PORT); 89 mInterrupted = true; 90 } 91 while (!mInterrupted) { 92 try { 93 Socket clientSocket = mTcpServerSocket.accept(); 94 95 if (V) Log.v(TAG, "Socket connected!"); 96 TestTcpTransport transport = new TestTcpTransport(clientSocket); 97 Message msg = Message.obtain(); 98 msg.setTarget(mCallback); 99 msg.what = MSG_INCOMING_BTOPP_CONNECTION; 100 msg.obj = transport; 101 msg.sendToTarget(); 102 103 } catch (IOException e) { 104 Log.e(TAG, "Error accept connection " + e); 105 } 106 } 107 if (V) Log.v(TAG, "TCP listen thread finished"); 108 } else { 109 boolean serverOK = true; 110 111 /* 112 * it's possible that create will fail in some cases. 113 * retry for 10 times 114 */ 115 for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) { 116 try { 117 if (V) Log.v(TAG, "Starting RFCOMM listener...."); 118 mBtServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord("OBEX Object Push", BluetoothUuid.ObexObjectPush.getUuid()); 119 if (V) Log.v(TAG, "Started RFCOMM listener...."); 120 } catch (IOException e1) { 121 Log.e(TAG, "Error create RfcommServerSocket " + e1); 122 serverOK = false; 123 } 124 125 if (!serverOK) { 126 synchronized (this) { 127 try { 128 if (V) Log.v(TAG, "Wait 300 ms"); 129 Thread.sleep(300); 130 } catch (InterruptedException e) { 131 Log.e(TAG, "socketAcceptThread thread was interrupted (3)"); 132 mInterrupted = true; 133 } 134 } 135 } else { 136 break; 137 } 138 } 139 if (!serverOK) { 140 Log.e(TAG, "Error start listening after " + CREATE_RETRY_TIME + " try"); 141 mInterrupted = true; 142 } 143 if (!mInterrupted) { 144 Log.i(TAG, "Accept thread started."); 145 } 146 BluetoothSocket clientSocket; 147 while (!mInterrupted) { 148 try { 149 if (V) Log.v(TAG, "Accepting connection..."); 150 if (mBtServerSocket == null) { 151 152 } 153 BluetoothServerSocket sSocket = mBtServerSocket; 154 if (sSocket ==null) { 155 mInterrupted = true; 156 157 } else { 158 clientSocket = sSocket.accept(); 159 if (V) Log.v(TAG, "Accepted connection from " 160 + clientSocket.getRemoteDevice()); 161 BluetoothOppRfcommTransport transport = new BluetoothOppRfcommTransport( 162 clientSocket); 163 Message msg = Message.obtain(); 164 msg.setTarget(mCallback); 165 msg.what = MSG_INCOMING_BTOPP_CONNECTION; 166 msg.obj = transport; 167 msg.sendToTarget(); 168 } 169 } catch (IOException e) { 170 Log.e(TAG, "Error accept connection " + e); 171 try { 172 Thread.sleep(500); 173 } catch (InterruptedException ie) {} 174 } 175 } 176 Log.i(TAG, "BluetoothSocket listen thread finished"); 177 } 178 } 179 }; 180 mInterrupted = false; 181 if(!Constants.USE_TCP_SIMPLE_SERVER) { 182 mSocketAcceptThread.start(); 183 } 184 } 185 return true; 186 } 187 188 public synchronized void stop() { 189 if (mSocketAcceptThread != null) { 190 Log.i(TAG, "stopping Accept Thread"); 191 192 mInterrupted = true; 193 if (Constants.USE_TCP_DEBUG) { 194 if (V) Log.v(TAG, "close mTcpServerSocket"); 195 if (mTcpServerSocket != null) { 196 try { 197 mTcpServerSocket.close(); 198 mTcpServerSocket = null; 199 } catch (IOException e) { 200 Log.e(TAG, "Error close mTcpServerSocket"); 201 } 202 } 203 } else { 204 if (V) Log.v(TAG, "close mBtServerSocket"); 205 206 if (mBtServerSocket != null) { 207 try { 208 mBtServerSocket.close(); 209 mBtServerSocket = null; 210 } catch (IOException e) { 211 Log.e(TAG, "Error close mBtServerSocket"); 212 } 213 } 214 } 215 try { 216 mSocketAcceptThread.interrupt(); 217 if (V) Log.v(TAG, "waiting for thread to terminate"); 218 //mSocketAcceptThread.join(JOIN_TIMEOUT_MS); 219 mSocketAcceptThread.join(); 220 if (V) Log.v(TAG, "done waiting for thread to terminate"); 221 mSocketAcceptThread = null; 222 mCallback = null; 223 } catch (InterruptedException e) { 224 if (V) Log.v(TAG, "Interrupted waiting for Accept Thread to join"); 225 } 226 } 227 } 228} 229