View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2008 Michael Lifshits
4    *  Copyright (C) 2008 Vlad Skarzhevskyy
5    *
6    *  Licensed to the Apache Software Foundation (ASF) under one
7    *  or more contributor license agreements.  See the NOTICE file
8    *  distributed with this work for additional information
9    *  regarding copyright ownership.  The ASF licenses this file
10   *  to you under the Apache License, Version 2.0 (the
11   *  "License"); you may not use this file except in compliance
12   *  with the License.  You may obtain a copy of the License at
13   *
14   *    http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing,
17   *  software distributed under the License is distributed on an
18   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19   *  KIND, either express or implied.  See the License for the
20   *  specific language governing permissions and limitations
21   *  under the License.
22   *
23   *  @author vlads
24   *  @version $Id: BluetoothEmulator.java 2471 2008-12-01 03:44:20Z skarzhevskyy $
25   */
26  package com.intel.bluetooth;
27  
28  import java.io.IOException;
29  
30  import javax.bluetooth.BluetoothStateException;
31  import javax.bluetooth.DeviceClass;
32  import javax.bluetooth.DiscoveryListener;
33  import javax.bluetooth.RemoteDevice;
34  import javax.bluetooth.ServiceRegistrationException;
35  import javax.bluetooth.UUID;
36  
37  class BluetoothEmulator implements BluetoothStack {
38  
39  	static final int NATIVE_LIBRARY_VERSION = BlueCoveImpl.nativeLibraryVersionExpected;
40  
41  	private EmulatorLocalDevice localDevice;
42  
43  	private EmulatorDeviceInquiry deviceInquiry;
44  
45  	BluetoothEmulator() {
46  	}
47  
48  	// --- Library initialization
49  
50  	public String getStackID() {
51  		return BlueCoveImpl.STACK_EMULATOR;
52  	}
53  
54  	public String toString() {
55  		if (localDevice != null) {
56  			return getStackID() + ":" + RemoteDeviceHelper.getBluetoothAddress(localDevice.getAddress());
57  		} else {
58  			return getStackID();
59  		}
60  	}
61  
62  	/*
63  	 * (non-Javadoc)
64  	 * 
65  	 * @see com.intel.bluetooth.BluetoothStack#isNativeCodeLoaded()
66  	 */
67  	public boolean isNativeCodeLoaded() {
68  		return true;
69  	}
70  
71  	/*
72  	 * (non-Javadoc)
73  	 * 
74  	 * @see com.intel.bluetooth.BluetoothStack#requireNativeLibraries()
75  	 */
76  	public LibraryInformation[] requireNativeLibraries() {
77  		return null;
78  	}
79  
80  	public int getLibraryVersion() throws BluetoothStateException {
81  		return NATIVE_LIBRARY_VERSION;
82  	}
83  
84  	public int detectBluetoothStack() {
85  		return BlueCoveImpl.BLUECOVE_STACK_DETECT_EMULATOR;
86  	}
87  
88  	public void initialize() throws BluetoothStateException {
89  		localDevice = EmulatorHelper.createNewLocalDevice();
90  	}
91  
92  	public void destroy() {
93  		EmulatorHelper.releaseDevice(localDevice);
94  		localDevice = null;
95  	}
96  
97  	public void enableNativeDebug(Class nativeDebugCallback, boolean on) {
98  	}
99  
100 	/*
101 	 * (non-Javadoc)
102 	 * 
103 	 * @see com.intel.bluetooth.BluetoothStack#isCurrentThreadInterruptedCallback()
104 	 */
105 	public boolean isCurrentThreadInterruptedCallback() {
106 		return Thread.interrupted();
107 	}
108 
109 	/*
110 	 * (non-Javadoc)
111 	 * 
112 	 * @see com.intel.bluetooth.BluetoothStack#getFeatureSet()
113 	 */
114 	public int getFeatureSet() {
115 		return FEATURE_SET_DEVICE_SERVICE_CLASSES | FEATURE_SERVICE_ATTRIBUTES | FEATURE_L2CAP;
116 	}
117 
118 	// --- LocalDevice
119 
120 	private void assertClosed() {
121 		if (localDevice == null) {
122 			throw new RuntimeException("Device Closed");
123 		}
124 	}
125 
126 	public String getLocalDeviceBluetoothAddress() throws BluetoothStateException {
127 		assertClosed();
128 		return RemoteDeviceHelper.getBluetoothAddress(localDevice.getAddress());
129 	}
130 
131 	public DeviceClass getLocalDeviceClass() {
132 		assertClosed();
133 		return new DeviceClass(localDevice.getDeviceClass());
134 	}
135 
136 	public String getLocalDeviceName() {
137 		assertClosed();
138 		return localDevice.getName();
139 	}
140 
141 	public boolean isLocalDevicePowerOn() {
142 		assertClosed();
143 		return localDevice.isLocalDevicePowerOn();
144 	}
145 
146 	public String getLocalDeviceProperty(String property) {
147 		assertClosed();
148 		return localDevice.getLocalDeviceProperty(property);
149 	}
150 
151 	public int getLocalDeviceDiscoverable() {
152 		assertClosed();
153 		return localDevice.getLocalDeviceDiscoverable();
154 	}
155 
156 	public boolean setLocalDeviceDiscoverable(int mode) throws BluetoothStateException {
157 		assertClosed();
158 		return localDevice.setLocalDeviceDiscoverable(mode);
159 	}
160 
161 	private EmulatorLocalDevice activeLocalDevice() throws BluetoothStateException {
162 		assertClosed();
163 		if (!localDevice.isActive()) {
164 			throw new BluetoothStateException("Bluetooth system is off");
165 		}
166 		return localDevice;
167 	}
168 
169 	/*
170 	 * (non-Javadoc)
171 	 * 
172 	 * @see com.intel.bluetooth.BluetoothStack#setLocalDeviceServiceClasses(int)
173 	 */
174 	public void setLocalDeviceServiceClasses(int classOfDevice) {
175 		assertClosed();
176 		localDevice.setLocalDeviceServiceClasses(classOfDevice);
177 	}
178 
179 	// --- Remote Device authentication
180 
181 	public boolean authenticateRemoteDevice(long address) throws IOException {
182 		return false;
183 	}
184 
185 	/*
186 	 * (non-Javadoc)
187 	 * 
188 	 * @see com.intel.bluetooth.BluetoothStack#authenticateRemoteDevice(long, java.lang.String)
189 	 */
190 	public boolean authenticateRemoteDevice(long address, String passkey) throws IOException {
191 		return false;
192 	}
193 
194 	/*
195 	 * (non-Javadoc)
196 	 * 
197 	 * @see com.intel.bluetooth.BluetoothStack#removeAuthenticationWithRemoteDevice (long)
198 	 */
199 	public void removeAuthenticationWithRemoteDevice(long address) throws IOException {
200 		throw new NotSupportedIOException(getStackID());
201 	}
202 
203 	// --- Device Inquiry
204 
205 	public boolean startInquiry(int accessCode, DiscoveryListener listener) throws BluetoothStateException {
206 		if (deviceInquiry != null) {
207 			throw new BluetoothStateException("Another inquiry already running");
208 		}
209 		deviceInquiry = new EmulatorDeviceInquiry(activeLocalDevice(), this, listener);
210 		return DeviceInquiryThread.startInquiry(this, deviceInquiry, accessCode, listener);
211 	}
212 
213 	public boolean cancelInquiry(DiscoveryListener listener) {
214 		assertClosed();
215 		if (deviceInquiry == null) {
216 			return false;
217 		}
218 		if (deviceInquiry.cancelInquiry(listener)) {
219 			deviceInquiry = null;
220 			return true;
221 		} else {
222 			return false;
223 		}
224 	}
225 
226 	public String getRemoteDeviceFriendlyName(long address) throws IOException {
227 		return activeLocalDevice().getDeviceManagerService().getRemoteDeviceFriendlyName(address);
228 	}
229 
230 	public RemoteDevice[] retrieveDevices(int option) {
231 		return null;
232 	}
233 
234 	public Boolean isRemoteDeviceTrusted(long address) {
235 		return null;
236 	}
237 
238 	public Boolean isRemoteDeviceAuthenticated(long address) {
239 		return null;
240 	}
241 
242 	// --- Service search
243 
244 	public int searchServices(int[] attrSet, UUID[] uuidSet, RemoteDevice device, DiscoveryListener listener)
245 			throws BluetoothStateException {
246 		return SearchServicesThread.startSearchServices(this, new EmulatorSearchServices(activeLocalDevice(), this),
247 				attrSet, uuidSet, device, listener);
248 	}
249 
250 	public boolean cancelServiceSearch(int transID) {
251 		assertClosed();
252 		SearchServicesThread sst = SearchServicesThread.getServiceSearchThread(transID);
253 		if (sst != null) {
254 			synchronized (sst) {
255 				if (!sst.isTerminated()) {
256 					sst.setTerminated();
257 					return true;
258 				}
259 			}
260 		}
261 		return false;
262 	}
263 
264 	public boolean populateServicesRecordAttributeValues(ServiceRecordImpl serviceRecord, int[] attrIDs)
265 			throws IOException {
266 		if (attrIDs.length > localDevice.getBluetooth_sd_attr_retrievable_max()) {
267 			throw new IllegalArgumentException();
268 		}
269 		return EmulatorSearchServices.populateServicesRecordAttributeValues(activeLocalDevice(), serviceRecord,
270 				attrIDs, RemoteDeviceHelper.getAddress(serviceRecord.getHostDevice()), serviceRecord.getHandle());
271 	}
272 
273 	// --- Client RFCOMM connections
274 
275 	public long connectionRfOpenClientConnection(BluetoothConnectionParams params) throws IOException {
276 		EmulatorRFCOMMClient c = activeLocalDevice().createRFCOMMClient(params.address);
277 		boolean success = false;
278 		try {
279 			c.connect(params);
280 			success = true;
281 		} finally {
282 			if (!success) {
283 				localDevice.removeConnection(c);
284 			}
285 		}
286 		return c.getHandle();
287 	}
288 
289 	public void connectionRfCloseClientConnection(long handle) throws IOException {
290 		assertClosed();
291 		if (localDevice == null) {
292 			return;
293 		}
294 		EmulatorRFCOMMClient c = ((EmulatorRFCOMMClient) localDevice.getConnection(handle));
295 		try {
296 			c.close();
297 		} finally {
298 			if (localDevice != null) {
299 				localDevice.removeConnection(c);
300 			}
301 		}
302 	}
303 
304 	public int rfGetSecurityOpt(long handle, int expected) throws IOException {
305 		assertClosed();
306 		return ((EmulatorLinkedConnection) localDevice.getConnection(handle)).getSecurityOpt(expected);
307 	}
308 
309 	/*
310 	 * (non-Javadoc)
311 	 * 
312 	 * @see com.intel.bluetooth.BluetoothStack#l2Encrypt(long,long,boolean)
313 	 */
314 	public boolean rfEncrypt(long address, long handle, boolean on) throws IOException {
315 		assertClosed();
316 		return ((EmulatorLinkedConnection) localDevice.getConnection(handle)).encrypt(address, on);
317 	}
318 
319 	// --- Server RFCOMM connections
320 
321 	public long rfServerOpen(BluetoothConnectionNotifierParams params, ServiceRecordImpl serviceRecord)
322 			throws IOException {
323 		EmulatorRFCOMMService s = activeLocalDevice().createRFCOMMService();
324 		boolean success = false;
325 		try {
326 			s.open(params);
327 			serviceRecord.setHandle(s.getHandle());
328 			serviceRecord
329 					.populateRFCOMMAttributes(s.getHandle(), s.getChannel(), params.uuid, params.name, params.obex);
330 			s.updateServiceRecord(serviceRecord);
331 			success = true;
332 		} finally {
333 			if (!success) {
334 				localDevice.removeConnection(s);
335 			}
336 		}
337 		return s.getHandle();
338 	}
339 
340 	public void rfServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
341 		assertClosed();
342 		if (localDevice == null) {
343 			return;
344 		}
345 		EmulatorRFCOMMService s = ((EmulatorRFCOMMService) localDevice.getConnection(handle));
346 		try {
347 			s.close(serviceRecord);
348 		} finally {
349 			if (localDevice != null) {
350 				localDevice.removeConnection(s);
351 			}
352 		}
353 	}
354 
355 	private void serverUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen)
356 			throws ServiceRegistrationException {
357 		EmulatorServiceConnection s;
358 		try {
359 			s = ((EmulatorServiceConnection) activeLocalDevice().getConnection(handle));
360 		} catch (IOException e) {
361 			throw new ServiceRegistrationException(e.getMessage());
362 		}
363 		s.updateServiceRecord(serviceRecord);
364 	}
365 
366 	public void rfServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen)
367 			throws ServiceRegistrationException {
368 		serverUpdateServiceRecord(handle, serviceRecord, acceptAndOpen);
369 	}
370 
371 	public long rfServerAcceptAndOpenRfServerConnection(long handle) throws IOException {
372 		EmulatorRFCOMMService s = ((EmulatorRFCOMMService) activeLocalDevice().getConnection(handle));
373 		if (!localDevice.isConnectable()) {
374 			throw new BluetoothStateException("Local device is not connectable");
375 		}
376 		long clientHandle = 0;
377 		boolean success = false;
378 		while (!success) {
379 			long connectionHandle = s.accept();
380 			try {
381 				long remoteAddress = localDevice.getDeviceManagerService().getRemoteAddress(localDevice.getAddress(),
382 						connectionHandle);
383 				EmulatorRFCOMMClient c = localDevice.createRFCOMMClient(remoteAddress);
384 				c.connect(remoteAddress, connectionHandle);
385 				localDevice.getDeviceManagerService().connectionAccepted(localDevice.getAddress(), connectionHandle);
386 				success = true;
387 				clientHandle = c.getHandle();
388 			} catch (IOException e) {
389 				DebugLog.debug("fail to accept connection", e);
390 				continue;
391 			} finally {
392 				if (!success) {
393 					localDevice.getDeviceManagerService().closeConnection(localDevice.getAddress(), connectionHandle);
394 				}
395 			}
396 		}
397 		return clientHandle;
398 	}
399 
400 	public void connectionRfCloseServerConnection(long handle) throws IOException {
401 		connectionRfCloseClientConnection(handle);
402 	}
403 
404 	// --- Shared Client and Server RFCOMM connections
405 
406 	public int connectionRfRead(long handle) throws IOException {
407 		return ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).read();
408 	}
409 
410 	public int connectionRfRead(long handle, byte[] b, int off, int len) throws IOException {
411 		return ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).read(b, off, len);
412 	}
413 
414 	public int connectionRfReadAvailable(long handle) throws IOException {
415 		return ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).available();
416 	}
417 
418 	public void connectionRfWrite(long handle, int b) throws IOException {
419 		((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).write(b);
420 	}
421 
422 	public void connectionRfWrite(long handle, byte[] b, int off, int len) throws IOException {
423 		((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).write(b, off, len);
424 	}
425 
426 	public void connectionRfFlush(long handle) throws IOException {
427 		((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).flush();
428 	}
429 
430 	public long getConnectionRfRemoteAddress(long handle) throws IOException {
431 		return ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).getRemoteAddress();
432 	}
433 
434 	// --- Client and Server L2CAP connections
435 
436 	private void validateMTU(int receiveMTU, int transmitMTU) {
437 		if (receiveMTU > localDevice.getBluetooth_l2cap_receiveMTU_max()) {
438 			throw new IllegalArgumentException("invalid ReceiveMTU value " + receiveMTU);
439 		}
440 	}
441 
442 	public long l2OpenClientConnection(BluetoothConnectionParams params, int receiveMTU, int transmitMTU)
443 			throws IOException {
444 		validateMTU(receiveMTU, transmitMTU);
445 		EmulatorL2CAPClient c = activeLocalDevice().createL2CAPClient(params.address);
446 		boolean success = false;
447 		try {
448 			c.connect(params, receiveMTU, transmitMTU);
449 			success = true;
450 		} finally {
451 			if (!success) {
452 				localDevice.removeConnection(c);
453 			}
454 		}
455 		return c.getHandle();
456 	}
457 
458 	public void l2CloseClientConnection(long handle) throws IOException {
459 		assertClosed();
460 		EmulatorL2CAPClient c = ((EmulatorL2CAPClient) localDevice.getConnection(handle));
461 		try {
462 			c.close();
463 		} finally {
464 			localDevice.removeConnection(c);
465 		}
466 	}
467 
468 	public long l2ServerOpen(BluetoothConnectionNotifierParams params, int receiveMTU, int transmitMTU,
469 			ServiceRecordImpl serviceRecord) throws IOException {
470 		validateMTU(receiveMTU, transmitMTU);
471 		EmulatorL2CAPService s = activeLocalDevice().createL2CAPService(params.bluecove_ext_psm);
472 		boolean success = false;
473 		try {
474 			s.open(params, receiveMTU, transmitMTU);
475 			serviceRecord.setHandle(s.getHandle());
476 			serviceRecord.populateL2CAPAttributes((int) s.getHandle(), s.getPcm(), params.uuid, params.name);
477 			s.updateServiceRecord(serviceRecord);
478 			success = true;
479 		} finally {
480 			if (!success) {
481 				localDevice.removeConnection(s);
482 			}
483 		}
484 		return s.getHandle();
485 	}
486 
487 	public void l2ServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen)
488 			throws ServiceRegistrationException {
489 		serverUpdateServiceRecord(handle, serviceRecord, acceptAndOpen);
490 	}
491 
492 	public long l2ServerAcceptAndOpenServerConnection(long handle) throws IOException {
493 		EmulatorL2CAPService s = ((EmulatorL2CAPService) activeLocalDevice().getConnection(handle));
494 		if (!localDevice.isConnectable()) {
495 			throw new BluetoothStateException("Local device is not connectable");
496 		}
497 		long clientHandle = 0;
498 		boolean success = false;
499 		while (!success) {
500 			long connectionHandle = s.accept();
501 			try {
502 				long remoteAddress = localDevice.getDeviceManagerService().getRemoteAddress(localDevice.getAddress(),
503 						connectionHandle);
504 				EmulatorL2CAPClient c = localDevice.createL2CAPClient(remoteAddress);
505 				c.connect(remoteAddress, connectionHandle, s.getReceiveMTU(), s.getTransmitMTU());
506 				localDevice.getDeviceManagerService().connectionAccepted(localDevice.getAddress(), connectionHandle);
507 				success = true;
508 				clientHandle = c.getHandle();
509 			} catch (IOException e) {
510 				DebugLog.debug("fail to accept connection", e);
511 				continue;
512 			} finally {
513 				if (!success) {
514 					localDevice.getDeviceManagerService().closeConnection(localDevice.getAddress(), connectionHandle);
515 				}
516 			}
517 		}
518 		return clientHandle;
519 	}
520 
521 	public void l2CloseServerConnection(long handle) throws IOException {
522 		l2CloseClientConnection(handle);
523 	}
524 
525 	public void l2ServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
526 		assertClosed();
527 		EmulatorL2CAPService s = ((EmulatorL2CAPService) localDevice.getConnection(handle));
528 		try {
529 			s.close(serviceRecord);
530 		} finally {
531 			localDevice.removeConnection(s);
532 		}
533 	}
534 
535 	public int l2GetSecurityOpt(long handle, int expected) throws IOException {
536 		assertClosed();
537 		return ((EmulatorLinkedConnection) localDevice.getConnection(handle)).getSecurityOpt(expected);
538 	}
539 
540 	public boolean l2Ready(long handle) throws IOException {
541 		return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).ready();
542 	}
543 
544 	public int l2Receive(long handle, byte[] inBuf) throws IOException {
545 		return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).receive(inBuf);
546 	}
547 
548 	public void l2Send(long handle, byte[] data) throws IOException {
549 		((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).send(data);
550 	}
551 
552 	public int l2GetReceiveMTU(long handle) throws IOException {
553 		return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).getReceiveMTU();
554 	}
555 
556 	public int l2GetTransmitMTU(long handle) throws IOException {
557 		return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).getTransmitMTU();
558 	}
559 
560 	public long l2RemoteAddress(long handle) throws IOException {
561 		return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).getRemoteAddress();
562 	}
563 
564 	/*
565 	 * (non-Javadoc)
566 	 * 
567 	 * @see com.intel.bluetooth.BluetoothStack#l2Encrypt(long,long,boolean)
568 	 */
569 	public boolean l2Encrypt(long address, long handle, boolean on) throws IOException {
570 		assertClosed();
571 		return ((EmulatorLinkedConnection) localDevice.getConnection(handle)).encrypt(address, on);
572 	}
573 }