Plugin code cleanup.

This commit is contained in:
akwizgran
2011-12-09 00:08:15 +00:00
parent 2494ff1a1e
commit 9abe920edb
7 changed files with 155 additions and 217 deletions

View File

@@ -1,28 +0,0 @@
package net.sf.briar.plugins;
import java.io.IOException;
import java.util.concurrent.Executor;
import net.sf.briar.api.plugins.Plugin;
import net.sf.briar.api.plugins.PluginExecutor;
public abstract class AbstractPlugin implements Plugin {
protected final Executor pluginExecutor;
protected boolean running = false; // Locking: this
protected AbstractPlugin(@PluginExecutor Executor pluginExecutor) {
this.pluginExecutor = pluginExecutor;
}
public synchronized void start() throws IOException {
if(running) throw new IllegalStateException();
running = true;
}
public synchronized void stop() throws IOException {
if(!running) throw new IllegalStateException();
running = false;
}
}

View File

@@ -24,11 +24,10 @@ import net.sf.briar.api.plugins.StreamPlugin;
import net.sf.briar.api.plugins.StreamPluginCallback; import net.sf.briar.api.plugins.StreamPluginCallback;
import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.transport.StreamTransportConnection; import net.sf.briar.api.transport.StreamTransportConnection;
import net.sf.briar.plugins.AbstractPlugin;
import net.sf.briar.util.OsUtils; import net.sf.briar.util.OsUtils;
import net.sf.briar.util.StringUtils; import net.sf.briar.util.StringUtils;
class BluetoothPlugin extends AbstractPlugin implements StreamPlugin { class BluetoothPlugin implements StreamPlugin {
public static final byte[] TRANSPORT_ID = public static final byte[] TRANSPORT_ID =
StringUtils.fromHexString("d99c9313c04417dcf22fc60d12a187ea" StringUtils.fromHexString("d99c9313c04417dcf22fc60d12a187ea"
@@ -38,16 +37,18 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(BluetoothPlugin.class.getName()); Logger.getLogger(BluetoothPlugin.class.getName());
private final Object discoveryLock = new Object(); private final Executor pluginExecutor;
private final StreamPluginCallback callback; private final StreamPluginCallback callback;
private final long pollingInterval; private final long pollingInterval;
private final Object discoveryLock = new Object();
private boolean running = false; // Locking: this
private LocalDevice localDevice = null; // Locking: this private LocalDevice localDevice = null; // Locking: this
private StreamConnectionNotifier socket = null; // Locking: this private StreamConnectionNotifier socket = null; // Locking: this
BluetoothPlugin(@PluginExecutor Executor pluginExecutor, BluetoothPlugin(@PluginExecutor Executor pluginExecutor,
StreamPluginCallback callback, long pollingInterval) { StreamPluginCallback callback, long pollingInterval) {
super(pluginExecutor); this.pluginExecutor = pluginExecutor;
this.callback = callback; this.callback = callback;
this.pollingInterval = pollingInterval; this.pollingInterval = pollingInterval;
} }
@@ -56,43 +57,33 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
return id; return id;
} }
@Override
public void start() throws IOException { public void start() throws IOException {
// Initialise the Bluetooth stack // Initialise the Bluetooth stack
try { try {
synchronized(this) { synchronized(this) {
super.start(); running = true;
localDevice = LocalDevice.getLocalDevice(); localDevice = LocalDevice.getLocalDevice();
if(LOG.isLoggable(Level.INFO)) }
LOG.info("Local address "
+ localDevice.getBluetoothAddress());
}
} catch(UnsatisfiedLinkError e) { } catch(UnsatisfiedLinkError e) {
// On Linux the user may need to install libbluetooth-dev // On Linux the user may need to install libbluetooth-dev
if(OsUtils.isLinux()) { if(OsUtils.isLinux())
pluginExecutor.execute(new Runnable() { callback.showMessage("BLUETOOTH_INSTALL_LIBS");
public void run() {
callback.showMessage("BLUETOOTH_INSTALL_LIBS");
}
});
}
throw new IOException(e.toString()); throw new IOException(e.toString());
} }
pluginExecutor.execute(new Runnable() { pluginExecutor.execute(new Runnable() {
public void run() { public void run() {
bindContactSocket(); bind();
} }
}); });
} }
private void bindContactSocket() { private void bind() {
String uuid; String uuid;
synchronized(this) { synchronized(this) {
if(!running) return; if(!running) return;
uuid = getUuid(); uuid = getUuid();
makeDeviceDiscoverable(); makeDeviceDiscoverable();
} }
// Bind the socket
String url = "btspp://localhost:" + uuid + ";name=RFCOMM"; String url = "btspp://localhost:" + uuid + ";name=RFCOMM";
StreamConnectionNotifier scn; StreamConnectionNotifier scn;
try { try {
@@ -103,21 +94,12 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
synchronized(this) { synchronized(this) {
if(!running) { if(!running) {
try { tryToClose(scn);
scn.close();
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.toString());
}
return; return;
} }
socket = scn; socket = scn;
} }
pluginExecutor.execute(new Runnable() { acceptContactConnections(scn);
public void run() {
acceptContactConnections();
}
});
} }
private synchronized String getUuid() { private synchronized String getUuid() {
@@ -151,30 +133,37 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
} }
private void acceptContactConnections() { private void tryToClose(StreamConnectionNotifier scn) {
try {
scn.close();
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
}
}
private void acceptContactConnections(StreamConnectionNotifier scn) {
while(true) { while(true) {
StreamConnectionNotifier scn;
StreamConnection s; StreamConnection s;
synchronized(this) {
if(!running) return;
scn = socket;
}
try { try {
s = scn.acceptAndOpen(); s = scn.acceptAndOpen();
} catch(IOException e) { } catch(IOException e) {
// This is expected when the socket is closed // This is expected when the socket is closed
if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString()); if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString());
tryToClose(scn);
return; return;
} }
BluetoothTransportConnection conn = BluetoothTransportConnection conn =
new BluetoothTransportConnection(s); new BluetoothTransportConnection(s);
callback.incomingConnectionCreated(conn); callback.incomingConnectionCreated(conn);
synchronized(this) {
if(!running) return;
}
} }
} }
@Override
public synchronized void stop() throws IOException { public synchronized void stop() throws IOException {
super.stop(); running = false;
localDevice = null;
if(socket != null) { if(socket != null) {
socket.close(); socket.close();
socket = null; socket = null;
@@ -201,11 +190,11 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
private void connectAndCallBack() { private void connectAndCallBack() {
Map<ContactId, TransportProperties> remote;
synchronized(this) { synchronized(this) {
if(!running) return; if(!running) return;
remote = callback.getRemoteProperties();
} }
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
Map<ContactId, String> discovered = discoverContactUrls(remote); Map<ContactId, String> discovered = discoverContactUrls(remote);
for(Entry<ContactId, String> e : discovered.entrySet()) { for(Entry<ContactId, String> e : discovered.entrySet()) {
ContactId c = e.getKey(); ContactId c = e.getKey();
@@ -268,11 +257,11 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
public StreamTransportConnection createConnection(ContactId c) { public StreamTransportConnection createConnection(ContactId c) {
Map<ContactId, TransportProperties> remote;
synchronized(this) { synchronized(this) {
if(!running) return null; if(!running) return null;
remote = callback.getRemoteProperties();
} }
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
if(!remote.containsKey(c)) return null; if(!remote.containsKey(c)) return null;
remote = Collections.singletonMap(c, remote.get(c)); remote = Collections.singletonMap(c, remote.get(c));
String url = discoverContactUrls(remote).get(c); String url = discoverContactUrls(remote).get(c);
@@ -293,6 +282,9 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
private StreamTransportConnection createInvitationConnection(int code, private StreamTransportConnection createInvitationConnection(int code,
long timeout) { long timeout) {
synchronized(this) {
if(!running) return null;
}
// The invitee's device may not be discoverable, so both parties must // The invitee's device may not be discoverable, so both parties must
// try to initiate connections // try to initiate connections
String uuid = convertInvitationCodeToUuid(code); String uuid = convertInvitationCodeToUuid(code);
@@ -370,7 +362,6 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
if(!running) return; if(!running) return;
makeDeviceDiscoverable(); makeDeviceDiscoverable();
} }
// Bind the socket
String url = "btspp://localhost:" + c.getUuid() + ";name=RFCOMM"; String url = "btspp://localhost:" + c.getUuid() + ";name=RFCOMM";
final StreamConnectionNotifier scn; final StreamConnectionNotifier scn;
try { try {
@@ -379,37 +370,26 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
return; return;
} }
// Close the socket when the invitation times out
pluginExecutor.execute(new Runnable() { pluginExecutor.execute(new Runnable() {
public void run() { public void run() {
acceptInvitationConnection(c, scn); try {
Thread.sleep(c.getTimeout());
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.INFO))
LOG.info("Interrupted while waiting for invitation");
Thread.currentThread().interrupt();
}
tryToClose(scn);
} }
}); });
// Close the socket when the invitation times out
try {
Thread.sleep(c.getTimeout());
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.INFO))
LOG.info("Interrupted while waiting for invitation timeout");
Thread.currentThread().interrupt();
}
try {
scn.close();
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
}
}
private void acceptInvitationConnection(ConnectionCallback c,
StreamConnectionNotifier scn) {
synchronized(this) {
if(!running) return;
}
try { try {
StreamConnection s = scn.acceptAndOpen(); StreamConnection s = scn.acceptAndOpen();
c.addConnection(s); c.addConnection(s);
} catch(IOException e) { } catch(IOException e) {
// This is expected when the socket is closed // This is expected when the socket is closed
if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString()); if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString());
tryToClose(scn);
} }
} }
} }

View File

@@ -17,18 +17,21 @@ import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.transport.BatchTransportReader; import net.sf.briar.api.transport.BatchTransportReader;
import net.sf.briar.api.transport.BatchTransportWriter; import net.sf.briar.api.transport.BatchTransportWriter;
import net.sf.briar.api.transport.TransportConstants; import net.sf.briar.api.transport.TransportConstants;
import net.sf.briar.plugins.AbstractPlugin;
import org.apache.commons.io.FileSystemUtils; import org.apache.commons.io.FileSystemUtils;
abstract class FilePlugin extends AbstractPlugin implements BatchPlugin { abstract class FilePlugin implements BatchPlugin {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(FilePlugin.class.getName()); Logger.getLogger(FilePlugin.class.getName());
protected final Executor pluginExecutor;
protected final BatchPluginCallback callback; protected final BatchPluginCallback callback;
protected volatile boolean running = false;
private final Object listenerLock = new Object(); private final Object listenerLock = new Object();
private FileListener listener = null; // Locking: listenerLock private FileListener listener = null; // Locking: listenerLock
protected abstract File chooseOutputDirectory(); protected abstract File chooseOutputDirectory();
@@ -38,7 +41,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
protected FilePlugin(@PluginExecutor Executor pluginExecutor, protected FilePlugin(@PluginExecutor Executor pluginExecutor,
BatchPluginCallback callback) { BatchPluginCallback callback) {
super(pluginExecutor); this.pluginExecutor = pluginExecutor;
this.callback = callback; this.callback = callback;
} }
@@ -47,6 +50,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
} }
public BatchTransportWriter createWriter(ContactId c) { public BatchTransportWriter createWriter(ContactId c) {
if(!running) return null;
return createWriter(createConnectionFilename()); return createWriter(createConnectionFilename());
} }
@@ -63,9 +67,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
} }
private BatchTransportWriter createWriter(String filename) { private BatchTransportWriter createWriter(String filename) {
synchronized(this) { if(!running) return null;
if(!running) return null;
}
File dir = chooseOutputDirectory(); File dir = chooseOutputDirectory();
if(dir == null || !dir.exists() || !dir.isDirectory()) return null; if(dir == null || !dir.exists() || !dir.isDirectory()) return null;
File f = new File(dir, filename); File f = new File(dir, filename);
@@ -85,26 +87,30 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
return FileSystemUtils.freeSpaceKb(path) * 1024L; return FileSystemUtils.freeSpaceKb(path) * 1024L;
} }
protected synchronized void createReaderFromFile(final File f) { protected void createReaderFromFile(final File f) {
if(!running) return; if(!running) return;
pluginExecutor.execute(new ReaderCreator(f)); pluginExecutor.execute(new ReaderCreator(f));
} }
public BatchTransportWriter sendInvitation(int code, long timeout) { public BatchTransportWriter sendInvitation(int code, long timeout) {
if(!running) return null;
return createWriter(createInvitationFilename(code, false)); return createWriter(createInvitationFilename(code, false));
} }
public BatchTransportReader acceptInvitation(int code, long timeout) { public BatchTransportReader acceptInvitation(int code, long timeout) {
if(!running) return null;
String filename = createInvitationFilename(code, false); String filename = createInvitationFilename(code, false);
return createInvitationReader(filename, timeout); return createInvitationReader(filename, timeout);
} }
public BatchTransportWriter sendInvitationResponse(int code, long timeout) { public BatchTransportWriter sendInvitationResponse(int code, long timeout) {
if(!running) return null;
return createWriter(createInvitationFilename(code, true)); return createWriter(createInvitationFilename(code, true));
} }
public BatchTransportReader acceptInvitationResponse(int code, public BatchTransportReader acceptInvitationResponse(int code,
long timeout) { long timeout) {
if(!running) return null;
String filename = createInvitationFilename(code, true); String filename = createInvitationFilename(code, true);
return createInvitationReader(filename, timeout); return createInvitationReader(filename, timeout);
} }
@@ -155,23 +161,23 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
private class ReaderCreator implements Runnable { private class ReaderCreator implements Runnable {
private final File f; private final File file;
private ReaderCreator(File f) { private ReaderCreator(File file) {
this.f = f; this.file = file;
} }
public void run() { public void run() {
String filename = f.getName(); String filename = file.getName();
if(isPossibleInvitationFilename(filename)) { if(isPossibleInvitationFilename(filename)) {
synchronized(listenerLock) { synchronized(listenerLock) {
if(listener != null) listener.addFile(f); if(listener != null) listener.addFile(file);
} }
} }
if(isPossibleConnectionFilename(f.getName())) { if(isPossibleConnectionFilename(file.getName())) {
try { try {
FileInputStream in = new FileInputStream(f); FileInputStream in = new FileInputStream(file);
callback.readerCreated(new FileTransportReader(f, in, callback.readerCreated(new FileTransportReader(file, in,
FilePlugin.this)); FilePlugin.this));
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) if(LOG.isLoggable(Level.WARNING))

View File

@@ -41,15 +41,13 @@ implements RemovableDriveMonitor.Callback {
return id; return id;
} }
@Override public void start() throws IOException {
public synchronized void start() throws IOException { running = true;
super.start();
monitor.start(this); monitor.start(this);
} }
@Override public void stop() throws IOException {
public synchronized void stop() throws IOException { running = false;
super.stop();
monitor.stop(); monitor.stop();
} }

View File

@@ -37,6 +37,9 @@ class LanSocketPlugin extends SimpleSocketPlugin {
@Override @Override
public StreamTransportConnection sendInvitation(int code, long timeout) { public StreamTransportConnection sendInvitation(int code, long timeout) {
synchronized(this) {
if(!running) return null;
}
// Calculate the group address and port from the invitation code // Calculate the group address and port from the invitation code
InetSocketAddress mcast = convertInvitationCodeToMulticastGroup(code); InetSocketAddress mcast = convertInvitationCodeToMulticastGroup(code);
// Bind a multicast socket for receiving packets // Bind a multicast socket for receiving packets
@@ -48,15 +51,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
ms.joinGroup(mcast.getAddress()); ms.joinGroup(mcast.getAddress());
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
if(ms != null) { if(ms != null) tryToClose(ms, mcast.getAddress());
try {
ms.leaveGroup(mcast.getAddress());
} catch(IOException e1) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e1.toString());
}
ms.close();
}
return null; return null;
} }
// Listen until a valid packet is received or the timeout occurs // Listen until a valid packet is received or the timeout occurs
@@ -77,8 +72,6 @@ class LanSocketPlugin extends SimpleSocketPlugin {
try { try {
// Connect back on the advertised TCP port // Connect back on the advertised TCP port
Socket s = new Socket(packet.getAddress(), port); Socket s = new Socket(packet.getAddress(), port);
ms.leaveGroup(mcast.getAddress());
ms.close();
return new SocketTransportConnection(s); return new SocketTransportConnection(s);
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) if(LOG.isLoggable(Level.WARNING))
@@ -89,21 +82,29 @@ class LanSocketPlugin extends SimpleSocketPlugin {
break; break;
} }
now = System.currentTimeMillis(); now = System.currentTimeMillis();
synchronized(this) {
if(!running) return null;
}
} }
if(LOG.isLoggable(Level.INFO)) if(LOG.isLoggable(Level.INFO))
LOG.info("Timeout while sending invitation"); LOG.info("Timeout while sending invitation");
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
try { } finally {
ms.leaveGroup(mcast.getAddress()); tryToClose(ms, mcast.getAddress());
} catch(IOException e1) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e1.toString());
}
ms.close();
} }
return null; return null;
} }
private void tryToClose(MulticastSocket ms, InetAddress addr) {
try {
ms.leaveGroup(addr);
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
}
ms.close();
}
private InetSocketAddress convertInvitationCodeToMulticastGroup(int code) { private InetSocketAddress convertInvitationCodeToMulticastGroup(int code) {
Random r = new Random(code); Random r = new Random(code);
byte[] b = new byte[5]; byte[] b = new byte[5];
@@ -139,6 +140,9 @@ class LanSocketPlugin extends SimpleSocketPlugin {
@Override @Override
public StreamTransportConnection acceptInvitation(int code, long timeout) { public StreamTransportConnection acceptInvitation(int code, long timeout) {
synchronized(this) {
if(!running) return null;
}
// Calculate the group address and port from the invitation code // Calculate the group address and port from the invitation code
InetSocketAddress mcast = convertInvitationCodeToMulticastGroup(code); InetSocketAddress mcast = convertInvitationCodeToMulticastGroup(code);
// Bind a TCP socket for receiving connections // Bind a TCP socket for receiving connections
@@ -149,14 +153,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
ss.bind(new InetSocketAddress(iface, 0)); ss.bind(new InetSocketAddress(iface, 0));
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
if(ss != null) { if(ss != null) tryToClose(ss);
try {
ss.close();
} catch(IOException e1) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e1.toString());
}
}
return null; return null;
} }
// Bind a multicast socket for sending packets // Bind a multicast socket for sending packets
@@ -168,12 +165,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
if(ms != null) ms.close(); if(ms != null) ms.close();
try { tryToClose(ss);
ss.close();
} catch(IOException e1) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e1.toString());
}
return null; return null;
} }
// Send packets until a connection is received or the timeout expires // Send packets until a connection is received or the timeout expires
@@ -201,6 +193,9 @@ class LanSocketPlugin extends SimpleSocketPlugin {
interval += 1000; interval += 1000;
} }
} }
synchronized(this) {
if(!running) return null;
}
} }
if(LOG.isLoggable(Level.INFO)) if(LOG.isLoggable(Level.INFO))
LOG.info("Timeout while accepting invitation"); LOG.info("Timeout while accepting invitation");
@@ -208,13 +203,16 @@ class LanSocketPlugin extends SimpleSocketPlugin {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
} finally { } finally {
ms.close(); ms.close();
try { tryToClose(ss);
ss.close();
} catch(IOException e1) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e1.toString());
}
} }
return null; return null;
} }
private void tryToClose(ServerSocket ss) {
try {
ss.close();
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
}
}
} }

View File

@@ -63,10 +63,8 @@ class SimpleSocketPlugin extends SocketPlugin {
return new ServerSocket(); return new ServerSocket();
} }
// Locking: this
@Override @Override
protected SocketAddress getLocalSocketAddress() { protected SocketAddress getLocalSocketAddress() {
assert running;
SocketAddress addr = createSocketAddress(callback.getLocalProperties()); SocketAddress addr = createSocketAddress(callback.getLocalProperties());
if(addr == null) { if(addr == null) {
try { try {
@@ -112,17 +110,13 @@ class SimpleSocketPlugin extends SocketPlugin {
throw new IOException("No suitable interfaces"); throw new IOException("No suitable interfaces");
} }
// Locking: this
@Override @Override
protected SocketAddress getRemoteSocketAddress(ContactId c) { protected SocketAddress getRemoteSocketAddress(ContactId c) {
assert running;
TransportProperties p = callback.getRemoteProperties().get(c); TransportProperties p = callback.getRemoteProperties().get(c);
return p == null ? null : createSocketAddress(p); return p == null ? null : createSocketAddress(p);
} }
// Locking: this
private SocketAddress createSocketAddress(TransportProperties p) { private SocketAddress createSocketAddress(TransportProperties p) {
assert running;
assert p != null; assert p != null;
String host = p.get("external"); String host = p.get("external");
if(host == null) host = p.get("internal"); if(host == null) host = p.get("internal");
@@ -137,10 +131,8 @@ class SimpleSocketPlugin extends SocketPlugin {
return new InetSocketAddress(host, port); return new InetSocketAddress(host, port);
} }
// Locking: this
@Override @Override
protected void setLocalSocketAddress(SocketAddress s) { protected void setLocalSocketAddress(SocketAddress s) {
assert running;
if(!(s instanceof InetSocketAddress)) if(!(s instanceof InetSocketAddress))
throw new IllegalArgumentException(); throw new IllegalArgumentException();
InetSocketAddress i = (InetSocketAddress) s; InetSocketAddress i = (InetSocketAddress) s;

View File

@@ -15,21 +15,20 @@ import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.plugins.StreamPlugin; import net.sf.briar.api.plugins.StreamPlugin;
import net.sf.briar.api.plugins.StreamPluginCallback; import net.sf.briar.api.plugins.StreamPluginCallback;
import net.sf.briar.api.transport.StreamTransportConnection; import net.sf.briar.api.transport.StreamTransportConnection;
import net.sf.briar.plugins.AbstractPlugin;
abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin { abstract class SocketPlugin implements StreamPlugin {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(SocketPlugin.class.getName()); Logger.getLogger(SocketPlugin.class.getName());
protected final Executor pluginExecutor;
protected final StreamPluginCallback callback; protected final StreamPluginCallback callback;
protected boolean running = false; // Locking: this
protected ServerSocket socket = null; // Locking: this protected ServerSocket socket = null; // Locking: this
protected abstract void setLocalSocketAddress(SocketAddress s); protected abstract void setLocalSocketAddress(SocketAddress s);
// These methods must only be called with this's lock held and
// started == true
protected abstract Socket createClientSocket() throws IOException; protected abstract Socket createClientSocket() throws IOException;
protected abstract ServerSocket createServerSocket() throws IOException; protected abstract ServerSocket createServerSocket() throws IOException;
protected abstract SocketAddress getLocalSocketAddress(); protected abstract SocketAddress getLocalSocketAddress();
@@ -37,13 +36,14 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
protected SocketPlugin(@PluginExecutor Executor pluginExecutor, protected SocketPlugin(@PluginExecutor Executor pluginExecutor,
StreamPluginCallback callback) { StreamPluginCallback callback) {
super(pluginExecutor); this.pluginExecutor = pluginExecutor;
this.callback = callback; this.callback = callback;
} }
@Override public void start() throws IOException {
public synchronized void start() throws IOException { synchronized(this) {
super.start(); running = true;
}
pluginExecutor.execute(new Runnable() { pluginExecutor.execute(new Runnable() {
public void run() { public void run() {
bind(); bind();
@@ -55,78 +55,72 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
SocketAddress addr; SocketAddress addr;
ServerSocket ss = null; ServerSocket ss = null;
try { try {
synchronized(this) { addr = getLocalSocketAddress();
if(!running) return; ss = createServerSocket();
addr = getLocalSocketAddress();
ss = createServerSocket();
if(addr == null || ss == null) return;
}
ss.bind(addr);
if(LOG.isLoggable(Level.INFO)) {
LOG.info("Bound to " + ss.getInetAddress().getHostAddress()
+ ":" + ss.getLocalPort());
}
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
if(ss != null) { return;
try { }
ss.close(); if(addr == null || ss == null) return;
} catch(IOException e1) { try {
if(LOG.isLoggable(Level.WARNING)) ss.bind(addr);
LOG.warning(e1.toString()); } catch(IOException e) {
} if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
} tryToClose(ss);
return; return;
} }
synchronized(this) { synchronized(this) {
if(!running) { if(!running) {
try { tryToClose(ss);
ss.close();
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.toString());
}
return; return;
} }
socket = ss; socket = ss;
setLocalSocketAddress(ss.getLocalSocketAddress());
} }
// Accept connections until the socket is closed setLocalSocketAddress(ss.getLocalSocketAddress());
acceptContactConnections(ss);
}
private void tryToClose(ServerSocket ss) {
try {
ss.close();
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
}
}
private void acceptContactConnections(ServerSocket ss) {
while(true) { while(true) {
Socket s; Socket s;
synchronized(this) {
if(!running) return;
}
try { try {
s = ss.accept(); s = ss.accept();
} catch(IOException e) { } catch(IOException e) {
// This is expected when the socket is closed // This is expected when the socket is closed
if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString()); if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString());
try { tryToClose(ss);
ss.close();
} catch(IOException e1) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e1.toString());
}
return; return;
} }
SocketTransportConnection conn = new SocketTransportConnection(s); SocketTransportConnection conn = new SocketTransportConnection(s);
callback.incomingConnectionCreated(conn); callback.incomingConnectionCreated(conn);
synchronized(this) {
if(!running) return;
}
} }
} }
@Override
public synchronized void stop() throws IOException { public synchronized void stop() throws IOException {
super.stop(); running = false;
if(socket != null) socket.close(); if(socket != null) {
socket.close();
socket = null;
}
} }
public void poll() { public void poll() {
Map<ContactId, TransportProperties> remote;
synchronized(this) { synchronized(this) {
if(!running) return; if(!running) return;
remote = callback.getRemoteProperties();
} }
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
for(final ContactId c : remote.keySet()) { for(final ContactId c : remote.keySet()) {
pluginExecutor.execute(new Runnable() { pluginExecutor.execute(new Runnable() {
public void run() { public void run() {
@@ -142,20 +136,18 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
} }
public StreamTransportConnection createConnection(ContactId c) { public StreamTransportConnection createConnection(ContactId c) {
SocketAddress addr; synchronized(this) {
Socket s; if(!running) return null;
}
SocketAddress addr = getRemoteSocketAddress(c);
try { try {
synchronized(this) { Socket s = createClientSocket();
if(!running) return null; if(addr == null || s == null) return null;
addr = getRemoteSocketAddress(c);
s = createClientSocket();
if(addr == null || s == null) return null;
}
s.connect(addr); s.connect(addr);
return new SocketTransportConnection(s);
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString()); if(LOG.isLoggable(Level.INFO)) LOG.info(e.toString());
return null; return null;
} }
return new SocketTransportConnection(s);
} }
} }