Bluetooth plugin (untested).

This commit is contained in:
akwizgran
2011-10-06 19:33:12 +01:00
parent 6d68fa5c4a
commit 8fa77b57da
2 changed files with 246 additions and 0 deletions

View File

@@ -0,0 +1,216 @@
package net.sf.briar.plugins.bluetooth;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Executor;
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.LocalDevice;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.io.StreamConnectionNotifier;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportId;
import net.sf.briar.api.transport.InvalidConfigException;
import net.sf.briar.api.transport.InvalidPropertiesException;
import net.sf.briar.api.transport.stream.StreamTransportCallback;
import net.sf.briar.api.transport.stream.StreamTransportConnection;
import net.sf.briar.api.transport.stream.StreamTransportPlugin;
import net.sf.briar.plugins.AbstractPlugin;
class BluetoothPlugin extends AbstractPlugin implements StreamTransportPlugin {
public static final int TRANSPORT_ID = 2;
private static final TransportId id = new TransportId(TRANSPORT_ID);
private final String uuid;
private final long pollingInterval;
private StreamTransportCallback callback = null;
private StreamConnectionNotifier streamConnectionNotifier = null;
BluetoothPlugin(Executor executor, String uuid, long pollingInterval) {
super(executor);
this.uuid = uuid;
this.pollingInterval = pollingInterval;
}
public TransportId getId() {
return id;
}
public synchronized void start(Map<String, String> localProperties,
Map<ContactId, Map<String, String>> remoteProperties,
Map<String, String> config, StreamTransportCallback callback)
throws InvalidPropertiesException, InvalidConfigException,
IOException {
super.start(localProperties, remoteProperties, config);
this.callback = callback;
executor.execute(createBinder());
}
public synchronized void stop() throws IOException {
super.stop();
if(streamConnectionNotifier != null) {
streamConnectionNotifier.close();
streamConnectionNotifier = null;
}
}
private Runnable createBinder() {
return new Runnable() {
public void run() {
bind();
}
};
}
private void bind() {
synchronized(this) {
if(!started) return;
}
// Initialise the Bluetooth stack
LocalDevice localDevice = null;
try {
localDevice = LocalDevice.getLocalDevice();
} catch(BluetoothStateException e) {
// FIXME: Logging
return;
}
// Try to make the device discoverable (requires root on Linux)
try {
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
} catch(BluetoothStateException e) {
// FIXME: Logging
try {
localDevice.setDiscoverable(DiscoveryAgent.LIAC);
} catch(BluetoothStateException e1) {
// FIXME: Logging
}
}
// Bind the port
String url = "btspp://localhost:" + uuid + ";name=" + uuid;
StreamConnectionNotifier scn;
try {
scn = (StreamConnectionNotifier) Connector.open(url);
} catch(IOException e) {
// FIXME: Logging
return;
}
synchronized(this) {
if(!started) return;
streamConnectionNotifier = scn;
setConnectionUrl(localDevice.getBluetoothAddress());
startListener();
}
}
private void startListener() {
new Thread() {
@Override
public void run() {
listen();
}
}.start();
}
private void listen() {
while(true) {
StreamConnectionNotifier scn;
StreamConnection s;
synchronized(this) {
if(!started) return;
scn = streamConnectionNotifier;
}
try {
s = scn.acceptAndOpen();
} catch(IOException e) {
// FIXME: Logging
return;
}
synchronized(this) {
if(!started) {
try {
s.close();
} catch(IOException e) {
// FIXME: Logging
}
return;
}
BluetoothTransportConnection conn =
new BluetoothTransportConnection(s);
callback.incomingConnectionCreated(conn);
}
}
}
private void setConnectionUrl(String address) {
// Update the local properties with the connection URL
String url = "btspp://" + address + ":" + uuid + ";name=" + uuid;
Map<String, String> m = new TreeMap<String, String>(localProperties);
m.put("url", url);
callback.setLocalProperties(m);
}
public boolean shouldPoll() {
return true;
}
public long getPollingInterval() {
return pollingInterval;
}
public synchronized void poll() {
if(!started) return;
for(ContactId c : remoteProperties.keySet()) {
executor.execute(createConnector(c));
}
}
private Runnable createConnector(final ContactId c) {
return new Runnable() {
public void run() {
connect(c);
}
};
}
private StreamTransportConnection connect(ContactId c) {
StreamTransportConnection conn = createAndConnectSocket(c);
if(conn != null) {
synchronized(this) {
if(started) callback.outgoingConnectionCreated(c, conn);
}
}
return conn;
}
private StreamTransportConnection createAndConnectSocket(ContactId c) {
try {
String url;
synchronized(this) {
if(!started) return null;
Map<String, String> properties = remoteProperties.get(c);
if(properties == null) return null;
url = properties.get("url");
if(url == null) return null;
}
StreamConnection s = (StreamConnection) Connector.open(url);
return new BluetoothTransportConnection(s);
} catch(IOException e) {
// FIXME: Logging
return null;
}
}
public StreamTransportConnection createConnection(ContactId c) {
synchronized(this) {
if(!started) return null;
}
return createAndConnectSocket(c);
}
}

View File

@@ -0,0 +1,30 @@
package net.sf.briar.plugins.bluetooth;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.StreamConnection;
import net.sf.briar.api.transport.stream.StreamTransportConnection;
class BluetoothTransportConnection implements StreamTransportConnection {
private final StreamConnection stream;
BluetoothTransportConnection(StreamConnection stream) {
this.stream = stream;
}
public InputStream getInputStream() throws IOException {
return stream.openInputStream();
}
public OutputStream getOutputStream() throws IOException {
return stream.openOutputStream();
}
public void dispose(boolean success) throws IOException {
stream.close();
}
}