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: DeviceManagerServiceImpl.java 2600 2008-12-16 22:22:43Z skarzhevskyy $
25   */
26  package com.intel.bluetooth.emu;
27  
28  import java.io.IOException;
29  import java.util.Hashtable;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Vector;
34  
35  import javax.bluetooth.BluetoothConnectionException;
36  import javax.bluetooth.BluetoothStateException;
37  import javax.bluetooth.DiscoveryAgent;
38  import javax.bluetooth.ServiceRegistrationException;
39  
40  import com.intel.bluetooth.DebugLog;
41  import com.intel.bluetooth.RemoteDeviceHelper;
42  
43  public class DeviceManagerServiceImpl implements DeviceManagerService {
44  
45  	public static final int MAJOR_COMPUTER = 0x0100;
46  
47  	static final EmulatorConfiguration configuration;
48  
49  	private static Map<Long, Device> devices = new Hashtable<Long, Device>();
50  
51  	static {
52  		configuration = new EmulatorConfiguration();
53  		configuration.loadConfigFile();
54  	}
55  
56  	public DeviceManagerServiceImpl() {
57  	}
58  
59  	public void shutdown() {
60  		synchronized (devices) {
61  			for (Iterator<Device> iterator = devices.values().iterator(); iterator.hasNext();) {
62  				Device device = iterator.next();
63  				device.release();
64  			}
65  			devices.clear();
66  		}
67  	}
68  
69  	public DeviceDescriptor createNewDevice(String deviceID, String deviceAddress) throws BluetoothStateException {
70  		synchronized (devices) {
71  			long address = getNextAvailableBTAddress(deviceID, deviceAddress);
72  
73  			String name = configuration.getProperty(address, EmulatorConfiguration.deviceName);
74  			if (name == null) {
75  				name = configuration.getDeviceNamePrefix() + RemoteDeviceHelper.getBluetoothAddress(address);
76  			}
77  			int deviceClass = MAJOR_COMPUTER;
78  			String cod = configuration.getProperty(address, EmulatorConfiguration.deviceClass);
79  			if (cod != null) {
80  				deviceClass = EmulatorConfiguration.valueToInt(cod);
81  			}
82  			DeviceDescriptor descriptor = new DeviceDescriptor(address, name, deviceClass);
83  
84  			if (!configuration.isDeviceDiscoverable()) {
85  				descriptor.setDiscoverableMode(DiscoveryAgent.NOT_DISCOVERABLE);
86  			}
87  
88  			devices.put(new Long(address), new Device(descriptor));
89  			return descriptor;
90  		}
91  	}
92  
93  	public EmulatorConfiguration getEmulatorConfiguration(long localAddress) {
94  		return configuration.clone(localAddress);
95  	}
96  
97  	public void releaseDevice(long address) {
98  		Device device;
99  		synchronized (devices) {
100 			device = (Device) devices.remove(new Long(address));
101 		}
102 		if (device != null) {
103 			device.release();
104 		}
105 	}
106 
107 	public DeviceCommand pollCommand(long address) {
108 		Device device = getDevice(address);
109 		if (device == null) {
110 			throw new RuntimeException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
111 		}
112 		return device.pollCommand();
113 	}
114 
115 	static Device getDevice(long address) {
116 		Device d = ((Device) devices.get(new Long(address)));
117 		if ((d != null) && (!d.isAlive())) {
118 			synchronized (devices) {
119 				devices.remove(new Long(address));
120 			}
121 			d.died();
122 			return null;
123 		}
124 		return d;
125 	}
126 
127 	private Device getActiveDevice(long address) {
128 		Device d = getDevice(address);
129 		if ((d != null) && (!d.getDescriptor().isPoweredOn())) {
130 			return null;
131 		} else {
132 			return d;
133 		}
134 	}
135 
136 	public DeviceDescriptor getDeviceDescriptor(long address) {
137 		Device device = getDevice(address);
138 		if (device == null) {
139 			throw new RuntimeException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
140 		}
141 		return device.getDescriptor();
142 	}
143 
144 	private DeviceSDP getDeviceSDP(long address) {
145 		Device device = getActiveDevice(address);
146 		if (device == null) {
147 			return null;
148 		}
149 		return device.getDeviceSDP(false);
150 	}
151 
152 	public static List<MonitorDevice> getMonitorDevices() {
153 		Vector<MonitorDevice> monitorDevices = new Vector<MonitorDevice>();
154 		synchronized (devices) {
155 			for (Iterator<Device> iterator = devices.values().iterator(); iterator.hasNext();) {
156 				Device device = iterator.next();
157 				if (!device.isAlive()) {
158 					iterator.remove();
159 					device.died();
160 					continue;
161 				}
162 				isDiscoverable(device.getDescriptor());
163 				monitorDevices.add(new MonitorDevice(device));
164 			}
165 		}
166 		return monitorDevices;
167 	}
168 
169 	public DeviceDescriptor[] getDiscoveredDevices(long address) {
170 		Vector<DeviceDescriptor> discoveredDevice = new Vector<DeviceDescriptor>();
171 		synchronized (devices) {
172 			for (Iterator<Device> iterator = devices.values().iterator(); iterator.hasNext();) {
173 				Device device = iterator.next();
174 				if (!device.isAlive()) {
175 					iterator.remove();
176 					device.died();
177 					continue;
178 				}
179 				if (device.getDescriptor().getAddress() == address) {
180 					continue;
181 				}
182 				if (isDiscoverable(device.getDescriptor())) {
183 					discoveredDevice.addElement(device.getDescriptor());
184 				}
185 			}
186 		}
187 		return (DeviceDescriptor[]) discoveredDevice.toArray(new DeviceDescriptor[discoveredDevice.size()]);
188 	}
189 
190 	private static boolean isDiscoverable(DeviceDescriptor device) {
191 		if (!device.isPoweredOn()) {
192 			return false;
193 		}
194 		int discoverableMode = device.getDiscoverableMode();
195 		switch (discoverableMode) {
196 		case DiscoveryAgent.NOT_DISCOVERABLE:
197 			return false;
198 		case DiscoveryAgent.GIAC:
199 			return true;
200 		case DiscoveryAgent.LIAC:
201 			if (device.getLimitedDiscoverableStart() + configuration.getDurationLIAC() * 1000 * 60 < System
202 					.currentTimeMillis()) {
203 				DebugLog.debug(RemoteDeviceHelper.getBluetoothAddress(device.getAddress())
204 						+ " LIAC -> NOT_DISCOVERABLE");
205 				device.setDiscoverableMode(DiscoveryAgent.NOT_DISCOVERABLE);
206 				return false;
207 			} else {
208 				return true;
209 			}
210 		default:
211 			// No idea what are other modes are.
212 			return true;
213 		}
214 	}
215 
216 	public boolean isLocalDevicePowerOn(long localAddress) {
217 		return getDeviceDescriptor(localAddress).isPoweredOn();
218 	}
219 
220 	public void setLocalDevicePower(long localAddress, boolean on) {
221 		Device device = getDevice(localAddress);
222 		if (device == null) {
223 			throw new RuntimeException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
224 		}
225 		device.setDevicePower(on);
226 	}
227 
228 	public int getLocalDeviceDiscoverable(long localAddress) {
229 		DeviceDescriptor dd = getDeviceDescriptor(localAddress);
230 		if (!dd.isPoweredOn()) {
231 			return DiscoveryAgent.NOT_DISCOVERABLE;
232 		}
233 		// Update mode if it was LIAC
234 		isDiscoverable(dd);
235 		return dd.getDiscoverableMode();
236 	}
237 
238 	public boolean setLocalDeviceDiscoverable(long localAddress, int mode) throws BluetoothStateException {
239 		DeviceDescriptor dd = getDeviceDescriptor(localAddress);
240 		if (!dd.isPoweredOn()) {
241 			throw new BluetoothStateException("Device power is off");
242 		}
243 		DebugLog.debug(RemoteDeviceHelper.getBluetoothAddress(localAddress) + " setDiscoverableMode", EmulatorUtils
244 				.discoverableModeString(mode));
245 		dd.setDiscoverableMode(mode);
246 		return true;
247 	}
248 
249 	public void setLocalDeviceServiceClasses(long localAddress, int classOfDevice) {
250 		DebugLog.debug(RemoteDeviceHelper.getBluetoothAddress(localAddress) + " setServiceClasses ", classOfDevice);
251 		getDeviceDescriptor(localAddress).setDeviceClass(classOfDevice);
252 	}
253 
254 	public String getRemoteDeviceFriendlyName(long address) throws IOException {
255 		DeviceDescriptor dd = getDeviceDescriptor(address);
256 		if (!dd.isPoweredOn()) {
257 			throw new IOException("Remote device power is off");
258 		}
259 		return dd.getName();
260 	}
261 
262 	private long getNextAvailableBTAddress(String deviceID, String deviceAddress) throws BluetoothStateException {
263 		if (deviceID != null) {
264 			long id = configuration.getFirstDeviceAddress() + Long.parseLong(deviceID);
265 			if (getDevice(id) != null) {
266 				throw new BluetoothStateException("Device already reserved "
267 						+ RemoteDeviceHelper.getBluetoothAddress(id));
268 			}
269 			return id;
270 		} else if (deviceAddress != null) {
271 			long address = RemoteDeviceHelper.getAddress(deviceAddress);
272 			if (getDevice(address) != null) {
273 				throw new BluetoothStateException("Device already reserved "
274 						+ RemoteDeviceHelper.getBluetoothAddress(address));
275 			}
276 			return address;
277 		} else {
278 			return EmulatorUtils.getNextAvailable(devices.keySet(), configuration.getFirstDeviceAddress(), 1);
279 		}
280 
281 	}
282 
283 	public void updateServiceRecord(long address, long handle, ServicesDescriptor sdpData)
284 			throws ServiceRegistrationException {
285 		Device device = getActiveDevice(address);
286 		if (device == null) {
287 			throw new ServiceRegistrationException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
288 		}
289 		DeviceSDP ds = device.getDeviceSDP(true);
290 		ds.updateServiceRecord(handle, sdpData);
291 	}
292 
293 	public void removeServiceRecord(long address, long handle) throws IOException {
294 		DeviceSDP ds = getDeviceSDP(address);
295 		if (ds != null) {
296 			ds.removeServiceRecord(handle);
297 		}
298 	}
299 
300 	public long[] searchServices(long address, String[] uuidSet) {
301 		if (getActiveDevice(address) == null) {
302 			return null;
303 		}
304 		DeviceSDP ds = getDeviceSDP(address);
305 		if (ds == null) {
306 			return new long[0];
307 		}
308 		return ds.searchServices(uuidSet);
309 	}
310 
311 	public byte[] getServicesRecordBinary(long address, long handle) throws IOException {
312 		DeviceSDP ds = getDeviceSDP(address);
313 		if (ds == null) {
314 			throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
315 		}
316 		ServicesDescriptor sd = ds.getServicesDescriptor(handle);
317 		if (sd == null) {
318 			throw new IOException("No such service");
319 		}
320 		return sd.getSdpBinary();
321 	}
322 
323 	public void rfOpenService(long localAddress, int channel) throws IOException {
324 		openService(localAddress, ServiceListener.rfPrefix(channel));
325 	}
326 
327 	public long rfAccept(long localAddress, int channel, boolean authenticate, boolean encrypt) throws IOException {
328 		return accept(localAddress, ServiceListener.rfPrefix(channel), authenticate, encrypt, 0);
329 	}
330 
331 	public long rfConnect(long localAddress, long remoteAddress, int channel, boolean authenticate, boolean encrypt,
332 			int timeout) throws IOException {
333 		return connect(localAddress, remoteAddress, ServiceListener.rfPrefix(channel), authenticate, encrypt, 0,
334 				timeout);
335 	}
336 
337 	public void rfCloseService(long address, int pcm) {
338 		closeService(address, ServiceListener.rfPrefix(pcm));
339 	}
340 
341 	public void l2OpenService(long localAddress, int pcm) throws IOException {
342 		openService(localAddress, ServiceListener.l2Prefix(pcm));
343 	}
344 
345 	public long l2Accept(long localAddress, int channel, boolean authenticate, boolean encrypt, int receiveMTU)
346 			throws IOException {
347 		return accept(localAddress, ServiceListener.l2Prefix(channel), authenticate, encrypt, receiveMTU);
348 	}
349 
350 	public long l2Connect(long localAddress, long remoteAddress, int channel, boolean authenticate, boolean encrypt,
351 			int receiveMTU, int timeout) throws IOException {
352 		return connect(localAddress, remoteAddress, ServiceListener.l2Prefix(channel), authenticate, encrypt,
353 				receiveMTU, timeout);
354 	}
355 
356 	public void l2CloseService(long address, int channel) {
357 		closeService(address, ServiceListener.l2Prefix(channel));
358 	}
359 
360 	private long accept(long localAddress, String channelID, boolean authenticate, boolean encrypt, int receiveMTU)
361 			throws IOException {
362 		Device device;
363 		if ((device = getActiveDevice(localAddress)) == null) {
364 			throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
365 		}
366 		ServiceListener sl = device.createServiceListener(channelID);
367 		return sl.accept(device, authenticate, encrypt, receiveMTU);
368 	}
369 
370 	private long connect(long localAddress, long remoteAddress, String portID, boolean authenticate, boolean encrypt,
371 			int receiveMTU, int timeout) throws IOException {
372 		Device remoteDevice = getActiveDevice(remoteAddress);
373 		if (remoteDevice == null) {
374 			throw new BluetoothConnectionException(BluetoothConnectionException.FAILED_NOINFO, "No such device "
375 					+ RemoteDeviceHelper.getBluetoothAddress(remoteAddress));
376 		}
377 		Device localDevice = getActiveDevice(localAddress);
378 		if (localDevice == null) {
379 			throw new BluetoothConnectionException(BluetoothConnectionException.FAILED_NOINFO, "No such device "
380 					+ RemoteDeviceHelper.getBluetoothAddress(localAddress));
381 		}
382 		if (localDevice.getConnectionBuffer(remoteAddress, portID) != null) {
383 			throw new BluetoothConnectionException(BluetoothConnectionException.FAILED_NOINFO,
384 					"Already connected to the same port " + portID + " on "
385 							+ RemoteDeviceHelper.getBluetoothAddress(remoteAddress));
386 		}
387 		ServiceListener sl = remoteDevice.connectService(portID, timeout);
388 		if (sl == null) {
389 			throw new BluetoothConnectionException(BluetoothConnectionException.UNKNOWN_PSM, "No such service "
390 					+ portID);
391 		}
392 		return sl.connect(localDevice, authenticate, encrypt, receiveMTU, timeout);
393 	}
394 
395 	public void connectionAccepted(long localAddress, long connectionId) throws IOException {
396 		Device device;
397 		if ((device = getActiveDevice(localAddress)) == null) {
398 			throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
399 		}
400 		ConnectionBuffer c = device.getConnectionBuffer(connectionId);
401 		if (c == null) {
402 			throw new IOException("No such connection " + connectionId);
403 		}
404 		c.accepted();
405 	}
406 
407 	private void openService(long address, String channelID) throws IOException {
408 		Device device = getActiveDevice(address);
409 		if (device == null) {
410 			throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(address));
411 		}
412 		device.openService(channelID);
413 	}
414 
415 	private void closeService(long address, String channelID) {
416 		Device device = getDevice(address);
417 		if (device == null) {
418 			return;
419 		}
420 		device.closeService(channelID);
421 	}
422 
423 	private ConnectionBuffer getConnectionBuffer(long localAddress, long connectionId) throws IOException {
424 		Device localDevice = getActiveDevice(localAddress);
425 		if (localDevice == null) {
426 			throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
427 		}
428 		ConnectionBuffer c = localDevice.getConnectionBuffer(connectionId);
429 		if (c == null) {
430 			throw new IOException("No such connection " + connectionId);
431 		}
432 		return c;
433 	}
434 
435 	public long getRemoteAddress(long localAddress, long connectionId) throws IOException {
436 		return getConnectionBuffer(localAddress, connectionId).getRemoteAddress();
437 	}
438 
439 	public void rfWrite(long localAddress, long connectionId, byte[] b) throws IOException {
440 		((ConnectionBufferRFCOMM) getConnectionBuffer(localAddress, connectionId)).rfWrite(b);
441 	}
442 
443 	public void rfFlush(long localAddress, long connectionId) throws IOException {
444 		((ConnectionBufferRFCOMM) getConnectionBuffer(localAddress, connectionId)).rfFlush();
445 	}
446 
447 	public int rfAvailable(long localAddress, long connectionId) throws IOException {
448 		return ((ConnectionBufferRFCOMM) getConnectionBuffer(localAddress, connectionId)).rfAvailable();
449 	}
450 
451 	public byte[] rfRead(long localAddress, long connectionId, int len) throws IOException {
452 		return ((ConnectionBufferRFCOMM) getConnectionBuffer(localAddress, connectionId)).rfRead(len);
453 	}
454 
455 	public void closeConnection(long localAddress, long connectionId) throws IOException {
456 		Device localDevice = getDevice(localAddress);
457 		if (localDevice == null) {
458 			throw new IOException("No such device " + RemoteDeviceHelper.getBluetoothAddress(localAddress));
459 		}
460 		localDevice.closeConnection(connectionId);
461 	}
462 
463 	public int getSecurityOpt(long localAddress, long connectionId, int expected) throws IOException {
464 		return ((ConnectionBuffer) getConnectionBuffer(localAddress, connectionId)).getSecurityOpt(expected);
465 	}
466 
467 	public boolean encrypt(long localAddress, long connectionId, long remoteAddress, boolean on) throws IOException {
468 		return ((ConnectionBuffer) getConnectionBuffer(localAddress, connectionId)).encrypt(remoteAddress, on);
469 	}
470 
471 	public int l2RemoteDeviceReceiveMTU(long localAddress, long connectionId) throws IOException {
472 		return ((ConnectionBufferL2CAP) getConnectionBuffer(localAddress, connectionId)).getRemoteReceiveMTU();
473 	}
474 
475 	public boolean l2Ready(long localAddress, long connectionId) throws IOException {
476 		return ((ConnectionBufferL2CAP) getConnectionBuffer(localAddress, connectionId)).ready();
477 	}
478 
479 	public byte[] l2Receive(long localAddress, long connectionId, int len) throws IOException {
480 		return ((ConnectionBufferL2CAP) getConnectionBuffer(localAddress, connectionId)).receive(len);
481 	}
482 
483 	public void l2Send(long localAddress, long connectionId, byte[] data) throws IOException {
484 		((ConnectionBufferL2CAP) getConnectionBuffer(localAddress, connectionId)).send(data);
485 	}
486 }