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