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 33 package com.android.bluetooth.opp; 34 35 import java.io.IOException; 36 import java.net.ServerSocket; 37 import java.net.Socket; 38 39 import com.android.bluetooth.BluetoothObexTransport; 40 41 import android.bluetooth.BluetoothAdapter; 42 import android.bluetooth.BluetoothServerSocket; 43 import android.bluetooth.BluetoothSocket; 44 import android.bluetooth.BluetoothUuid; 45 import android.os.Handler; 46 import android.os.Message; 47 import android.util.Log; 48 49 /** 50 * This class listens on OPUSH channel for incoming connection 51 */ 52 public class BluetoothOppRfcommListener { 53 private static final String TAG = "BtOppRfcommListener"; 54 55 private static final boolean V = Constants.VERBOSE; 56 57 public static final int MSG_INCOMING_BTOPP_CONNECTION = 100; 58 59 private volatile boolean mInterrupted; 60 61 private Thread mSocketAcceptThread; 62 63 private Handler mCallback; 64 65 private static final int CREATE_RETRY_TIME = 10; 66 67 private final BluetoothAdapter mAdapter; 68 69 private BluetoothServerSocket mBtServerSocket = null; 70 71 private ServerSocket mTcpServerSocket = null; 72 73 public BluetoothOppRfcommListener(BluetoothAdapter adapter) { 74 mAdapter = adapter; 75 } 76 77 78 public synchronized boolean start(Handler callback) { 79 if (mSocketAcceptThread == null) { 80 mCallback = callback; 81 82 mSocketAcceptThread = new Thread(TAG) { 83 84 public void run() { 85 if (Constants.USE_TCP_DEBUG) { 86 try { 87 if (V) Log.v(TAG, "Create TCP ServerSocket"); 88 mTcpServerSocket = new ServerSocket(Constants.TCP_DEBUG_PORT, 1); 89 } catch (IOException e) { 90 Log.e(TAG, "Error listing on port" + Constants.TCP_DEBUG_PORT); 91 mInterrupted = true; 92 } 93 while (!mInterrupted) { 94 try { 95 Socket clientSocket = mTcpServerSocket.accept(); 96 97 if (V) Log.v(TAG, "Socket connected!"); 98 TestTcpTransport transport = new TestTcpTransport(clientSocket); 99 Message msg = Message.obtain(); 100 msg.setTarget(mCallback); 101 msg.what = MSG_INCOMING_BTOPP_CONNECTION; 102 msg.obj = transport; 103 msg.sendToTarget(); 104 105 } catch (IOException e) { 106 Log.e(TAG, "Error accept connection " + e); 107 } 108 } 109 if (V) Log.v(TAG, "TCP listen thread finished"); 110 } else { 111 boolean serverOK = true; 112 113 /* 114 * it's possible that create will fail in some cases. 115 * retry for 10 times 116 */ 117 for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) { 118 try { 119 if (V) Log.v(TAG, "Starting RFCOMM listener...."); 120 mBtServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord("OBEX Object Push", BluetoothUuid.ObexObjectPush.getUuid()); 121 if (V) Log.v(TAG, "Started RFCOMM listener...."); 122 } catch (IOException e1) { 123 Log.e(TAG, "Error create RfcommServerSocket " + e1); 124 serverOK = false; 125 } 126 127 if (!serverOK) { 128 synchronized (this) { 129 try { 130 if (V) Log.v(TAG, "Wait 300 ms"); 131 Thread.sleep(300); 132 } catch (InterruptedException e) { 133 Log.e(TAG, "socketAcceptThread thread was interrupted (3)"); 134 mInterrupted = true; 135 } 136 } 137 } else { 138 break; 139 } 140 } 141 if (!serverOK) { 142 Log.e(TAG, "Error start listening after " + CREATE_RETRY_TIME + " try"); 143 mInterrupted = true; 144 } 145 if (!mInterrupted) { 146 Log.i(TAG, "Accept thread started."); 147 } 148 BluetoothSocket clientSocket; 149 while (!mInterrupted) { 150 try { 151 if (V) Log.v(TAG, "Accepting connection..."); 152 if (mBtServerSocket == null) { 153 154 } 155 BluetoothServerSocket sSocket = mBtServerSocket; 156 if (sSocket ==null) { 157 mInterrupted = true; 158 159 } else { 160 clientSocket = sSocket.accept(); 161 if (V) Log.v(TAG, "Accepted connection from " 162 + clientSocket.getRemoteDevice()); 163 BluetoothObexTransport transport = new BluetoothObexTransport( 164 clientSocket); 165 Message msg = Message.obtain(); 166 msg.setTarget(mCallback); 167 msg.what = MSG_INCOMING_BTOPP_CONNECTION; 168 msg.obj = transport; 169 msg.sendToTarget(); 170 } 171 } catch (IOException e) { 172 Log.e(TAG, "Error accept connection " + e); 173 try { 174 Thread.sleep(500); 175 } catch (InterruptedException ie) {} 176 } 177 } 178 Log.i(TAG, "BluetoothSocket listen thread finished"); 179 } 180 } 181 }; 182 mInterrupted = false; 183 if(!Constants.USE_TCP_SIMPLE_SERVER) { 184 mSocketAcceptThread.start(); 185 } 186 } 187 return true; 188 } 189 190 public synchronized void stop() { 191 if (mSocketAcceptThread != null) { 192 Log.i(TAG, "stopping Accept Thread"); 193 194 mInterrupted = true; 195 if (Constants.USE_TCP_DEBUG) { 196 if (V) Log.v(TAG, "close mTcpServerSocket"); 197 if (mTcpServerSocket != null) { 198 try { 199 mTcpServerSocket.close(); 200 mTcpServerSocket = null; 201 } catch (IOException e) { 202 Log.e(TAG, "Error close mTcpServerSocket"); 203 } 204 } 205 } else { 206 if (V) Log.v(TAG, "close mBtServerSocket"); 207 208 if (mBtServerSocket != null) { 209 try { 210 mBtServerSocket.close(); 211 mBtServerSocket = null; 212 } catch (IOException e) { 213 Log.e(TAG, "Error close mBtServerSocket"); 214 } 215 } 216 } 217 try { 218 mSocketAcceptThread.interrupt(); 219 if (V) Log.v(TAG, "waiting for thread to terminate"); 220 //mSocketAcceptThread.join(JOIN_TIMEOUT_MS); 221 mSocketAcceptThread.join(); 222 if (V) Log.v(TAG, "done waiting for thread to terminate"); 223 mSocketAcceptThread = null; 224 mCallback = null; 225 } catch (InterruptedException e) { 226 if (V) Log.v(TAG, "Interrupted waiting for Accept Thread to join"); 227 } 228 } 229 } 230 } 231