BluetoothOppRfcommListener.java revision 52236de777c23788df8147de15912a57e8bc36dd
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; 38import java.net.SocketException; 39 40import android.bluetooth.BluetoothServerSocket; 41import android.bluetooth.BluetoothSocket; 42import android.os.Handler; 43import android.os.Message; 44import android.util.Log; 45 46/** 47 * This class listens on OPUSH channel for incoming connection 48 */ 49public class BluetoothOppRfcommListener { 50 private static final String TAG = "BtOpp RfcommListener"; 51 52 private volatile boolean mInterrupted; 53 54 private Thread mSocketAcceptThread; 55 56 private Handler mCallback; 57 58 private static final int ACCEPT_WAIT_TIMEOUT = 5000; 59 60 private static final int CREATE_RETRY_TIME = 10; 61 62 public static final int DEFAULT_OPP_CHANNEL = 12; 63 64 public static final int MSG_INCOMING_BTOPP_CONNECTION = 100; 65 66 private int mBtOppRfcommChannel = -1; 67 68 public BluetoothOppRfcommListener() { 69 this(DEFAULT_OPP_CHANNEL); 70 } 71 72 public BluetoothOppRfcommListener(int channel) { 73 mBtOppRfcommChannel = channel; 74 } 75 76 public synchronized boolean start(Handler callback) { 77 if (mSocketAcceptThread == null) { 78 mCallback = callback; 79 if (Constants.LOGV) { 80 Log.v(TAG, "create mSocketAcceptThread"); 81 } 82 mSocketAcceptThread = new Thread(TAG) { 83 84 public void run() { 85 if (Constants.LOGV) { 86 Log.v(TAG, "BluetoothOppRfcommListener thread starting"); 87 } 88 if (Constants.USE_TCP_DEBUG) { 89 ServerSocket mServerSocket = null; 90 try { 91 if (Constants.LOGVV) { 92 Log.v(TAG, "Create ServerSocket on port " 93 + Constants.TCP_DEBUG_PORT); 94 } 95 96 mServerSocket = new ServerSocket(Constants.TCP_DEBUG_PORT, 1); 97 98 } catch (IOException e) { 99 Log.e(TAG, "Error listing on port" + Constants.TCP_DEBUG_PORT); 100 mInterrupted = true; 101 } 102 while (!mInterrupted) { 103 try { 104 mServerSocket.setSoTimeout(ACCEPT_WAIT_TIMEOUT); 105 Socket clientSocket = mServerSocket.accept(); 106 107 if (clientSocket == null) { 108 if (Constants.LOGVV) { 109 Log.v(TAG, "incomming connection time out"); 110 } 111 } else { 112 if (Constants.LOGV) { 113 Log.v(TAG, "TCP Socket connected!"); 114 } 115 Log.d(TAG, "remote addr is " 116 + clientSocket.getRemoteSocketAddress()); 117 TestTcpTransport transport = new TestTcpTransport(clientSocket); 118 Message msg = Message.obtain(); 119 msg.setTarget(mCallback); 120 msg.what = MSG_INCOMING_BTOPP_CONNECTION; 121 msg.obj = transport; 122 msg.sendToTarget(); 123 } 124 } catch (SocketException e) { 125 if (Constants.LOGVV) { 126 Log.v(TAG, "Error accept connection " + e); 127 } 128 } catch (IOException e) { 129 if (Constants.LOGVV) { 130 Log.v(TAG, "Error accept connection " + e); 131 } 132 } 133 } 134 if (Constants.LOGV) { 135 Log.v(TAG, "TCP listen thread finished"); 136 } 137 try { 138 mServerSocket.close(); 139 } catch (IOException e) { 140 Log.e(TAG, "Error close mServerSocker " + e); 141 } 142 } else { 143 BluetoothServerSocket mServerSocket = null; 144 boolean serverOK = true; 145 146 /* 147 * it's possible that create will fail in some cases. 148 * retry for 10 times 149 */ 150 if (Constants.LOGVV) { 151 Log.v(TAG, "Create BluetoothServerSocket on channel " 152 + mBtOppRfcommChannel); 153 } 154 for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) { 155 try { 156 mServerSocket = BluetoothServerSocket 157 .listenUsingInsecureRfcommOn(mBtOppRfcommChannel); 158 } catch (IOException e1) { 159 Log.d(TAG, "Error create RfcommServerSocket " + e1); 160 serverOK = false; 161 } 162 if (!serverOK) { 163 synchronized (this) { 164 try { 165 if (Constants.LOGVV) { 166 Log.v(TAG, "wait 3 seconds"); 167 } 168 Thread.sleep(3000); 169 } catch (InterruptedException e) { 170 Log.e(TAG, "socketAcceptThread thread was interrupted (3)"); 171 mInterrupted = true; 172 } 173 } 174 } else { 175 break; 176 } 177 } 178 if (!serverOK) { 179 Log.e(TAG, "Error start listening after " + CREATE_RETRY_TIME + " try"); 180 mInterrupted = true; 181 } 182 183 BluetoothSocket clientSocket; 184 while (!mInterrupted) { 185 try { 186 clientSocket = mServerSocket.accept(ACCEPT_WAIT_TIMEOUT); 187 if (Constants.LOGVV) { 188 Log.v(TAG, "BluetoothSocket connected!"); 189 Log.v(TAG, "remote addr is " + clientSocket.getAddress()); 190 } 191 BluetoothOppRfcommTransport transport = new BluetoothOppRfcommTransport( 192 clientSocket); 193 Message msg = Message.obtain(); 194 msg.setTarget(mCallback); 195 msg.what = MSG_INCOMING_BTOPP_CONNECTION; 196 msg.obj = transport; 197 msg.sendToTarget(); 198 } catch (IOException e) { 199 //TODO later accept should not throw exception 200 if (Constants.LOGVV) { 201 //Log.v(TAG, "Error accept connection " + e); 202 } 203 } 204 } 205 try { 206 if (mServerSocket != null) { 207 if (Constants.LOGVV) { 208 Log.v(TAG, "close mServerSocket"); 209 } 210 mServerSocket.close(); 211 //TODO 212 //mServerSocket.destroy(); 213 } 214 } catch (IOException e) { 215 Log.e(TAG, "Errro close mServerSocket " + e); 216 } 217 if (Constants.LOGV) { 218 Log.v(TAG, "BluetoothSocket listen thread finished"); 219 } 220 } 221 } 222 }; 223 mInterrupted = false; 224 mSocketAcceptThread.start(); 225 } 226 return true; 227 } 228 229 public synchronized void stop() { 230 if (mSocketAcceptThread != null) { 231 if (Constants.LOGV) { 232 Log.v(TAG, "stopping Connect Thread"); 233 } 234 mInterrupted = true; 235 try { 236 mSocketAcceptThread.interrupt(); 237 if (Constants.LOGVV) { 238 Log.v(TAG, "waiting for thread to terminate"); 239 } 240 mSocketAcceptThread.join(); 241 mSocketAcceptThread = null; 242 mCallback = null; 243 } catch (InterruptedException e) { 244 if (Constants.LOGVV) { 245 Log.v(TAG, "Interrupted waiting for Accept Thread to join"); 246 } 247 } 248 } 249 } 250} 251