mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 14:19:53 +01:00
Moved some work off the UI thread and fixed a potential memory leak.
This commit is contained in:
@@ -12,6 +12,11 @@ public interface InvitationManager {
|
|||||||
*/
|
*/
|
||||||
InvitationTask getTask(int handle);
|
InvitationTask getTask(int handle);
|
||||||
|
|
||||||
/** Called by tasks to remove themselves when they terminate. */
|
/** Called by tasks to add themselves to the manager when they start. */
|
||||||
|
void putTask(int handle, InvitationTask task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by tasks to remove themselves from the managet when they finish.
|
||||||
|
*/
|
||||||
void removeTask(int handle);
|
void removeTask(int handle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,32 +4,41 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static net.sf.briar.api.plugins.InvitationConstants.CONFIRMATION_TIMEOUT;
|
import static net.sf.briar.api.plugins.InvitationConstants.CONFIRMATION_TIMEOUT;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.invitation.InvitationListener;
|
import net.sf.briar.api.invitation.InvitationListener;
|
||||||
import net.sf.briar.api.invitation.InvitationManager;
|
import net.sf.briar.api.invitation.InvitationManager;
|
||||||
import net.sf.briar.api.invitation.InvitationState;
|
import net.sf.briar.api.invitation.InvitationState;
|
||||||
import net.sf.briar.api.invitation.InvitationTask;
|
import net.sf.briar.api.invitation.InvitationTask;
|
||||||
|
import net.sf.briar.api.plugins.PluginManager;
|
||||||
|
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
|
||||||
|
import net.sf.briar.api.serial.ReaderFactory;
|
||||||
|
import net.sf.briar.api.serial.WriterFactory;
|
||||||
|
|
||||||
/** A task consisting of one or more parallel connection attempts. */
|
/** A task consisting of one or more parallel connection attempts. */
|
||||||
class ConnectorGroup implements InvitationTask {
|
class ConnectorGroup extends Thread implements InvitationTask {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ConnectorGroup.class.getName());
|
Logger.getLogger(ConnectorGroup.class.getName());
|
||||||
|
|
||||||
private final InvitationManager manager;
|
private final InvitationManager invitationManager;
|
||||||
|
private final CryptoComponent crypto;
|
||||||
|
private final ReaderFactory readerFactory;
|
||||||
|
private final WriterFactory writerFactory;
|
||||||
|
private final PluginManager pluginManager;
|
||||||
private final int handle, localInvitationCode, remoteInvitationCode;
|
private final int handle, localInvitationCode, remoteInvitationCode;
|
||||||
private final Collection<Connector> connectors;
|
|
||||||
private final Collection<InvitationListener> listeners;
|
private final Collection<InvitationListener> listeners;
|
||||||
private final AtomicBoolean connected;
|
private final AtomicBoolean connected;
|
||||||
private final CountDownLatch localConfirmationLatch;
|
private final CountDownLatch localConfirmationLatch;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All of the following are locking: this. We don't want to call the
|
* All of the following require locking: this. We don't want to call the
|
||||||
* listeners with a lock held, but we need to avoid a race condition in
|
* listeners with a lock held, but we need to avoid a race condition in
|
||||||
* addListener(), so the state that's accessed there after calling
|
* addListener(), so the state that's accessed there after calling
|
||||||
* listeners.add() must be guarded by a lock.
|
* listeners.add() must be guarded by a lock.
|
||||||
@@ -39,13 +48,18 @@ class ConnectorGroup implements InvitationTask {
|
|||||||
private boolean localCompared = false, remoteCompared = false;
|
private boolean localCompared = false, remoteCompared = false;
|
||||||
private boolean localMatched = false, remoteMatched = false;
|
private boolean localMatched = false, remoteMatched = false;
|
||||||
|
|
||||||
ConnectorGroup(InvitationManager manager, int handle,
|
ConnectorGroup(InvitationManager invitationManager, CryptoComponent crypto,
|
||||||
int localInvitationCode, int remoteInvitationCode) {
|
ReaderFactory readerFactory, WriterFactory writerFactory,
|
||||||
this.manager = manager;
|
PluginManager pluginManager, int handle, int localInvitationCode,
|
||||||
|
int remoteInvitationCode) {
|
||||||
|
this.invitationManager = invitationManager;
|
||||||
|
this.crypto = crypto;
|
||||||
|
this.readerFactory = readerFactory;
|
||||||
|
this.writerFactory = writerFactory;
|
||||||
|
this.pluginManager = pluginManager;
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
this.localInvitationCode = localInvitationCode;
|
this.localInvitationCode = localInvitationCode;
|
||||||
this.remoteInvitationCode = remoteInvitationCode;
|
this.remoteInvitationCode = remoteInvitationCode;
|
||||||
connectors = new CopyOnWriteArrayList<Connector>();
|
|
||||||
listeners = new CopyOnWriteArrayList<InvitationListener>();
|
listeners = new CopyOnWriteArrayList<InvitationListener>();
|
||||||
connected = new AtomicBoolean(false);
|
connected = new AtomicBoolean(false);
|
||||||
localConfirmationLatch = new CountDownLatch(1);
|
localConfirmationLatch = new CountDownLatch(1);
|
||||||
@@ -66,27 +80,50 @@ class ConnectorGroup implements InvitationTask {
|
|||||||
listeners.remove(l);
|
listeners.remove(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: The task isn't removed from the manager unless this is called
|
|
||||||
public void connect() {
|
public void connect() {
|
||||||
for(Connector c : connectors) c.start();
|
start();
|
||||||
new Thread() {
|
}
|
||||||
@Override
|
|
||||||
public void run() {
|
@Override
|
||||||
try {
|
public void run() {
|
||||||
for(Connector c : connectors) c.join();
|
// Add this task to the manager
|
||||||
} catch(InterruptedException e) {
|
invitationManager.putTask(handle, this);
|
||||||
if(LOG.isLoggable(WARNING))
|
// Start the connection threads
|
||||||
LOG.warning("Interrupted while waiting for connectors");
|
final Collection<Connector> connectors = new ArrayList<Connector>();
|
||||||
}
|
// Alice is the party with the smaller invitation code
|
||||||
if(!connected.get()) {
|
if(localInvitationCode < remoteInvitationCode) {
|
||||||
synchronized(ConnectorGroup.this) {
|
for(DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
|
||||||
connectionFailed = true;
|
Connector c = new AliceConnector(crypto, readerFactory,
|
||||||
}
|
writerFactory, this, plugin, localInvitationCode,
|
||||||
for(InvitationListener l : listeners) l.connectionFailed();
|
remoteInvitationCode);
|
||||||
}
|
connectors.add(c);
|
||||||
manager.removeTask(handle);
|
c.start();
|
||||||
}
|
}
|
||||||
}.start();
|
} else {
|
||||||
|
for(DuplexPlugin plugin: pluginManager.getInvitationPlugins()) {
|
||||||
|
Connector c = (new BobConnector(crypto, readerFactory,
|
||||||
|
writerFactory, this, plugin, localInvitationCode,
|
||||||
|
remoteInvitationCode));
|
||||||
|
connectors.add(c);
|
||||||
|
c.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wait for the connection threads to finish
|
||||||
|
try {
|
||||||
|
for(Connector c : connectors) c.join();
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.warning("Interrupted while waiting for connectors");
|
||||||
|
}
|
||||||
|
// If none of the threads connected, inform the listeners
|
||||||
|
if(!connected.get()) {
|
||||||
|
synchronized(this) {
|
||||||
|
connectionFailed = true;
|
||||||
|
}
|
||||||
|
for(InvitationListener l : listeners) l.connectionFailed();
|
||||||
|
}
|
||||||
|
// Remove this task from the manager
|
||||||
|
invitationManager.removeTask(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void localConfirmationSucceeded() {
|
public void localConfirmationSucceeded() {
|
||||||
@@ -104,10 +141,6 @@ class ConnectorGroup implements InvitationTask {
|
|||||||
localConfirmationLatch.countDown();
|
localConfirmationLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addConnector(Connector c) {
|
|
||||||
connectors.add(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean getAndSetConnected() {
|
boolean getAndSetConnected() {
|
||||||
return connected.getAndSet(true);
|
return connected.getAndSet(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package net.sf.briar.invitation;
|
package net.sf.briar.invitation;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -9,7 +8,6 @@ import net.sf.briar.api.crypto.CryptoComponent;
|
|||||||
import net.sf.briar.api.invitation.InvitationManager;
|
import net.sf.briar.api.invitation.InvitationManager;
|
||||||
import net.sf.briar.api.invitation.InvitationTask;
|
import net.sf.briar.api.invitation.InvitationTask;
|
||||||
import net.sf.briar.api.plugins.PluginManager;
|
import net.sf.briar.api.plugins.PluginManager;
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
|
|
||||||
import net.sf.briar.api.serial.ReaderFactory;
|
import net.sf.briar.api.serial.ReaderFactory;
|
||||||
import net.sf.briar.api.serial.WriterFactory;
|
import net.sf.briar.api.serial.WriterFactory;
|
||||||
|
|
||||||
@@ -37,30 +35,19 @@ class InvitationManagerImpl implements InvitationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public InvitationTask createTask(int localCode, int remoteCode) {
|
public InvitationTask createTask(int localCode, int remoteCode) {
|
||||||
Collection<DuplexPlugin> plugins = pluginManager.getInvitationPlugins();
|
|
||||||
int handle = nextHandle.incrementAndGet();
|
int handle = nextHandle.incrementAndGet();
|
||||||
ConnectorGroup group =
|
return new ConnectorGroup(this, crypto, readerFactory, writerFactory,
|
||||||
new ConnectorGroup(this, handle, localCode, remoteCode);
|
pluginManager, handle, localCode, remoteCode);
|
||||||
// Alice is the peer with the lesser invitation code
|
|
||||||
if(localCode < remoteCode) {
|
|
||||||
for(DuplexPlugin plugin : plugins) {
|
|
||||||
group.addConnector(new AliceConnector(crypto, readerFactory,
|
|
||||||
writerFactory, group, plugin, localCode, remoteCode));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(DuplexPlugin plugin : plugins) {
|
|
||||||
group.addConnector(new BobConnector(crypto, readerFactory,
|
|
||||||
writerFactory, group, plugin, localCode, remoteCode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tasks.put(handle, group);
|
|
||||||
return group;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public InvitationTask getTask(int handle) {
|
public InvitationTask getTask(int handle) {
|
||||||
return tasks.get(handle);
|
return tasks.get(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void putTask(int handle, InvitationTask task) {
|
||||||
|
tasks.put(handle, task);
|
||||||
|
}
|
||||||
|
|
||||||
public void removeTask(int handle) {
|
public void removeTask(int handle) {
|
||||||
tasks.remove(handle);
|
tasks.remove(handle);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user