Comments to indicate which locks guard which variables.

This commit is contained in:
akwizgran
2015-01-29 11:05:46 +00:00
parent 47bd84122e
commit 0dbfd7073f
21 changed files with 235 additions and 1092 deletions

View File

@@ -19,6 +19,9 @@ class FortunaGenerator {
private static final int KEY_BYTES = 32;
private static final int BLOCK_BYTES = 16;
private final Lock synchLock = new ReentrantLock();
// The following are locking: synchLock
private final MessageDigest digest = new DoubleDigest(new SHA256Digest());
private final BlockCipher cipher = new AESLightEngine();
private final byte[] key = new byte[KEY_BYTES];
@@ -26,8 +29,6 @@ class FortunaGenerator {
private final byte[] buffer = new byte[BLOCK_BYTES];
private final byte[] newKey = new byte[KEY_BYTES];
private final Lock synchLock = new ReentrantLock();
FortunaGenerator(byte[] seed) {
reseed(seed);
}

View File

@@ -316,12 +316,12 @@ abstract class JdbcDatabase implements Database<Connection> {
private final Clock clock;
private final LinkedList<Connection> connections =
new LinkedList<Connection>();
new LinkedList<Connection>(); // Locking: connectionsLock
private final AtomicInteger transactionCount = new AtomicInteger(0);
private int openConnections = 0;
private boolean closed = false;
private int openConnections = 0; // Locking: connectionsLock
private boolean closed = false; // Locking: connectionsLock
protected abstract Connection createConnection() throws SQLException;
protected abstract void flushBuffersToDisk(Statement s) throws SQLException;
@@ -444,7 +444,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} finally {
connectionsLock.unlock();
}
try {
if(txn == null) {
// Open a new connection

View File

@@ -62,12 +62,9 @@ class ConnectorGroup extends Thread implements InvitationTask {
private final Collection<InvitationListener> listeners;
private final AtomicBoolean connected;
private final CountDownLatch localConfirmationLatch;
private final Lock synchLock = new ReentrantLock();
/*The state that's accessed in addListener() after
* calling listeners.add() must be guarded by a lock.
*/
// The following are locking: synchLock
private int localConfirmationCode = -1, remoteConfirmationCode = -1;
private boolean connectionFailed = false;
private boolean localCompared = false, remoteCompared = false;

View File

@@ -9,12 +9,12 @@ import org.briarproject.api.lifecycle.ShutdownManager;
class ShutdownManagerImpl implements ShutdownManager {
protected final Map<Integer, Thread> hooks;
private int nextHandle = 0;
private final Lock synchLock = new ReentrantLock();
// The following are locking: synchLock
protected final Map<Integer, Thread> hooks;
private int nextHandle = 0;
ShutdownManagerImpl() {
hooks = new HashMap<Integer, Thread>();
}

View File

@@ -27,13 +27,12 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
Logger.getLogger(ConnectionRegistryImpl.class.getName());
private final EventBus eventBus;
// Locking: this
private final Map<TransportId, Map<ContactId, Integer>> connections;
// Locking: this
private final Map<ContactId, Integer> contactCounts;
private final Lock synchLock = new ReentrantLock();
// The following are locking: synchLock
private final Map<TransportId, Map<ContactId, Integer>> connections;
private final Map<ContactId, Integer> contactCounts;
@Inject
ConnectionRegistryImpl(EventBus eventBus) {
this.eventBus = eventBus;

View File

@@ -21,15 +21,17 @@ class Receiver implements ReadHandler {
private final Clock clock;
private final Sender sender;
private final SortedSet<Data> dataFrames;
private final Lock windowLock = new ReentrantLock();
private final Condition dataFrameAvailable = windowLock.newCondition();
// The following are locking: windowLock
private final SortedSet<Data> dataFrames;
private int windowSize = MAX_WINDOW_SIZE;
private long finalSequenceNumber = Long.MAX_VALUE;
private long nextSequenceNumber = 1;
private volatile boolean valid = true;
private Lock synchLock = new ReentrantLock();
private Condition dataFrameAvailable = synchLock.newCondition();
Receiver(Clock clock, Sender sender) {
this.sender = sender;
@@ -38,7 +40,7 @@ class Receiver implements ReadHandler {
}
Data read() throws IOException, InterruptedException {
synchLock.lock();
windowLock.lock();
try {
long now = clock.currentTimeMillis(), end = now + READ_TIMEOUT;
while(now < end && valid) {
@@ -64,17 +66,17 @@ class Receiver implements ReadHandler {
if(valid) throw new IOException("Read timed out");
throw new IOException("Connection closed");
} finally {
synchLock.unlock();
windowLock.unlock();
}
}
void invalidate() {
valid = false;
synchLock.lock();
windowLock.lock();
try {
dataFrameAvailable.signalAll();
} finally {
synchLock.unlock();
windowLock.unlock();
}
}
@@ -95,7 +97,7 @@ class Receiver implements ReadHandler {
}
private void handleData(byte[] b) throws IOException {
synchLock.lock();
windowLock.lock();
try {
if(b.length < Data.MIN_LENGTH || b.length > Data.MAX_LENGTH) {
// Ignore data frame with invalid length
@@ -134,7 +136,7 @@ class Receiver implements ReadHandler {
// Acknowledge the data frame even if it's a duplicate
sender.sendAck(sequenceNumber, windowSize);
} finally {
synchLock.unlock();
windowLock.unlock();
}
}

View File

@@ -26,8 +26,11 @@ class Sender {
private final Clock clock;
private final WriteHandler writeHandler;
private final LinkedList<Outstanding> outstanding;
private final Lock windowLock = new ReentrantLock();
private final Condition sendWindowAvailable = windowLock.newCondition();
// The following are locking: windowLock
private final LinkedList<Outstanding> outstanding;
private int outstandingBytes = 0;
private int windowSize = Data.MAX_PAYLOAD_LENGTH;
private int rtt = INITIAL_RTT, rttVar = INITIAL_RTT_VAR;
@@ -35,9 +38,6 @@ class Sender {
private long lastWindowUpdateOrProbe = Long.MAX_VALUE;
private boolean dataWaiting = false;
private Lock synchLock = new ReentrantLock();
private Condition sendWindowAvailable = synchLock.newCondition();
Sender(Clock clock, WriteHandler writeHandler) {
this.clock = clock;
this.writeHandler = writeHandler;
@@ -65,7 +65,7 @@ class Sender {
long sequenceNumber = a.getSequenceNumber();
long now = clock.currentTimeMillis();
Outstanding fastRetransmit = null;
synchLock.lock();
windowLock.lock();
try {
// Remove the acked data frame if it's outstanding
int foundIndex = -1;
@@ -105,7 +105,7 @@ class Sender {
if(windowSize > oldWindowSize || foundIndex != -1)
sendWindowAvailable.signalAll();
} finally {
synchLock.unlock();
windowLock.unlock();
}
// Fast retransmission
if(fastRetransmit != null)
@@ -116,7 +116,7 @@ class Sender {
long now = clock.currentTimeMillis();
List<Outstanding> retransmit = null;
boolean sendProbe = false;
synchLock.lock();
windowLock.lock();
try {
if(outstanding.isEmpty()) {
if(dataWaiting && now - lastWindowUpdateOrProbe > rto) {
@@ -147,7 +147,7 @@ class Sender {
}
}
} finally {
synchLock.unlock();
windowLock.unlock();
}
// Send a window probe if necessary
if(sendProbe) {
@@ -165,7 +165,7 @@ class Sender {
void write(Data d) throws IOException, InterruptedException {
int payloadLength = d.getPayloadLength();
synchLock.lock();
windowLock.lock();
try {
// Wait for space in the window
long now = clock.currentTimeMillis(), end = now + WRITE_TIMEOUT;
@@ -180,18 +180,18 @@ class Sender {
outstandingBytes += payloadLength;
dataWaiting = false;
} finally {
synchLock.unlock();
windowLock.unlock();
}
writeHandler.handleWrite(d.getBuffer());
}
void flush() throws IOException, InterruptedException {
synchLock.lock();
windowLock.lock();
try {
while(dataWaiting || !outstanding.isEmpty())
sendWindowAvailable.await();
} finally {
synchLock.unlock();
windowLock.unlock();
}
}

View File

@@ -50,14 +50,14 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
private final TagRecogniser tagRecogniser;
private final Clock clock;
private final Timer timer;
private final Lock synchLock = new ReentrantLock();
// The following are locking: synchLock
private final Map<TransportId, Integer> maxLatencies;
private final Map<EndpointKey, TemporarySecret> oldSecrets;
private final Map<EndpointKey, TemporarySecret> currentSecrets;
private final Map<EndpointKey, TemporarySecret> newSecrets;
private final Lock synchLock = new ReentrantLock();
@Inject
KeyManagerImpl(CryptoComponent crypto, DatabaseComponent db,
EventBus eventBus, TagRecogniser tagRecogniser, Clock clock,
@@ -121,6 +121,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
}
// Assigns secrets to the appropriate maps and returns any dead secrets
// Locking: synchLock
private Collection<TemporarySecret> assignSecretsToMaps(long now,
Collection<TemporarySecret> secrets) {
Collection<TemporarySecret> dead = new ArrayList<TemporarySecret>();
@@ -153,6 +154,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
}
// Replaces the given secrets and returns any secrets created
// Locking: synchLock
private Collection<TemporarySecret> replaceDeadSecrets(long now,
Collection<TemporarySecret> dead) {
// If there are several dead secrets for an endpoint, use the newest
@@ -253,7 +255,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
}
}
public synchronized void endpointAdded(Endpoint ep, int maxLatency,
public void endpointAdded(Endpoint ep, int maxLatency,
byte[] initialSecret) {
synchLock.lock();
try {
@@ -345,12 +347,14 @@ class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
}
}
// Locking: synchLock
private void removeSecrets(ContactId c, Map<?, TemporarySecret> m) {
Iterator<TemporarySecret> it = m.values().iterator();
while(it.hasNext())
if(it.next().getContactId().equals(c)) it.remove();
}
// Locking: synchLock
private void removeSecrets(TransportId t, Map<?, TemporarySecret> m) {
Iterator<TemporarySecret> it = m.values().iterator();
while(it.hasNext())

View File

@@ -1,546 +0,0 @@
package org.briarproject.transport;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimerTask;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
import javax.inject.Inject;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyManager;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.event.ContactRemovedEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.TransportAddedEvent;
import org.briarproject.api.event.TransportRemovedEvent;
import org.briarproject.api.system.Clock;
import org.briarproject.api.system.Timer;
import org.briarproject.api.transport.Endpoint;
import org.briarproject.api.transport.StreamContext;
import org.briarproject.api.transport.TagRecogniser;
import org.briarproject.api.transport.TemporarySecret;
// FIXME: Don't make alien calls with a lock held
class KeyManagerImpl extends TimerTask implements KeyManager, EventListener {
private static final int MS_BETWEEN_CHECKS = 60 * 1000;
private static final Logger LOG =
Logger.getLogger(KeyManagerImpl.class.getName());
private final CryptoComponent crypto;
private final DatabaseComponent db;
private final EventBus eventBus;
private final TagRecogniser tagRecogniser;
private final Clock clock;
private final Timer timer;
<<<<<<< HEAD
private final Map<TransportId, Long> maxLatencies;
=======
// All of the following are locking: this
private final Map<TransportId, Integer> maxLatencies;
>>>>>>> theSource
private final Map<EndpointKey, TemporarySecret> oldSecrets;
private final Map<EndpointKey, TemporarySecret> currentSecrets;
private final Map<EndpointKey, TemporarySecret> newSecrets;
private final Lock synchLock = new ReentrantLock();
@Inject
KeyManagerImpl(CryptoComponent crypto, DatabaseComponent db,
EventBus eventBus, TagRecogniser tagRecogniser, Clock clock,
Timer timer) {
this.crypto = crypto;
this.db = db;
this.eventBus = eventBus;
this.tagRecogniser = tagRecogniser;
this.clock = clock;
this.timer = timer;
maxLatencies = new HashMap<TransportId, Integer>();
oldSecrets = new HashMap<EndpointKey, TemporarySecret>();
currentSecrets = new HashMap<EndpointKey, TemporarySecret>();
newSecrets = new HashMap<EndpointKey, TemporarySecret>();
}
public boolean start() {
synchLock.lock();
try {
eventBus.addListener(this);
// Load the temporary secrets and transport latencies from the database
Collection<TemporarySecret> secrets;
try {
secrets = db.getSecrets();
maxLatencies.putAll(db.getTransportLatencies());
} catch(DbException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return false;
}
// Work out what phase of its lifecycle each secret is in
long now = clock.currentTimeMillis();
Collection<TemporarySecret> dead = assignSecretsToMaps(now, secrets);
// Replace any dead secrets
Collection<TemporarySecret> created = replaceDeadSecrets(now, dead);
if(!created.isEmpty()) {
// Store any secrets that have been created, removing any dead ones
try {
db.addSecrets(created);
} catch(DbException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return false;
}
}
// Pass the old, current and new secrets to the recogniser
for(TemporarySecret s : oldSecrets.values())
tagRecogniser.addSecret(s);
for(TemporarySecret s : currentSecrets.values())
tagRecogniser.addSecret(s);
for(TemporarySecret s : newSecrets.values())
tagRecogniser.addSecret(s);
// Schedule periodic key rotation
timer.scheduleAtFixedRate(this, MS_BETWEEN_CHECKS, MS_BETWEEN_CHECKS);
return true;
}
finally{
synchLock.unlock();
}
}
// Assigns secrets to the appropriate maps and returns any dead secrets
private Collection<TemporarySecret> assignSecretsToMaps(long now,
Collection<TemporarySecret> secrets) {
Collection<TemporarySecret> dead = new ArrayList<TemporarySecret>();
for(TemporarySecret s : secrets) {
// Discard the secret if the transport has been removed
Integer maxLatency = maxLatencies.get(s.getTransportId());
if(maxLatency == null) {
LOG.info("Discarding obsolete secret");
continue;
}
long rotation = maxLatency + MAX_CLOCK_DIFFERENCE;
long creationTime = s.getEpoch() + rotation * (s.getPeriod() - 2);
long activationTime = creationTime + rotation;
long deactivationTime = activationTime + rotation;
long destructionTime = deactivationTime + rotation;
if(now >= destructionTime) {
dead.add(s);
} else if(now >= deactivationTime) {
oldSecrets.put(new EndpointKey(s), s);
} else if(now >= activationTime) {
currentSecrets.put(new EndpointKey(s), s);
} else if(now >= creationTime) {
newSecrets.put(new EndpointKey(s), s);
} else {
// FIXME: Work out what to do here
throw new Error("Clock has moved backwards");
}
}
return dead;
}
<<<<<<< HEAD
// Replaces and erases the given secrets and returns any secrets created
=======
// Replaces the given secrets and returns any secrets created
// Locking: this
>>>>>>> theSource
private Collection<TemporarySecret> replaceDeadSecrets(long now,
Collection<TemporarySecret> dead) {
// If there are several dead secrets for an endpoint, use the newest
Map<EndpointKey, TemporarySecret> newest =
new HashMap<EndpointKey, TemporarySecret>();
for(TemporarySecret s : dead) {
EndpointKey k = new EndpointKey(s);
TemporarySecret exists = newest.get(k);
if(exists == null) {
// There's no other secret for this endpoint
newest.put(k, s);
} else if(exists.getPeriod() < s.getPeriod()) {
// There's an older secret - use this one instead
newest.put(k, s);
} else {
// There's a newer secret - keep using it
}
}
Collection<TemporarySecret> created = new ArrayList<TemporarySecret>();
for(Entry<EndpointKey, TemporarySecret> e : newest.entrySet()) {
TemporarySecret s = e.getValue();
Integer maxLatency = maxLatencies.get(s.getTransportId());
if(maxLatency == null) throw new IllegalStateException();
// Work out which rotation period we're in
long elapsed = now - s.getEpoch();
long rotation = maxLatency + MAX_CLOCK_DIFFERENCE;
long period = (elapsed / rotation) + 1;
if(period < 1) throw new IllegalStateException();
if(period - s.getPeriod() < 2)
throw new IllegalStateException();
// Derive the old, current and new secrets
byte[] b1 = s.getSecret();
for(long p = s.getPeriod() + 1; p < period; p++)
b1 = crypto.deriveNextSecret(b1, p);
byte[] b2 = crypto.deriveNextSecret(b1, period);
byte[] b3 = crypto.deriveNextSecret(b2, period + 1);
// Add the secrets to their respective maps if not already present
EndpointKey k = e.getKey();
if(!oldSecrets.containsKey(k)) {
TemporarySecret s1 = new TemporarySecret(s, period - 1, b1);
oldSecrets.put(k, s1);
created.add(s1);
}
if(!currentSecrets.containsKey(k)) {
TemporarySecret s2 = new TemporarySecret(s, period, b2);
currentSecrets.put(k, s2);
created.add(s2);
}
if(!newSecrets.containsKey(k)) {
TemporarySecret s3 = new TemporarySecret(s, period + 1, b3);
newSecrets.put(k, s3);
created.add(s3);
}
}
return created;
}
<<<<<<< HEAD
public boolean stop() {
synchLock.lock();
try{
eventBus.removeListener(this);
timer.cancel();
tagRecogniser.removeSecrets();
maxLatencies.clear();
removeAndEraseSecrets(oldSecrets);
removeAndEraseSecrets(currentSecrets);
removeAndEraseSecrets(newSecrets);
return true;
}
finally{
synchLock.unlock();
}
}
private void removeAndEraseSecrets(Map<?, TemporarySecret> m) {
for(TemporarySecret s : m.values()) ByteUtils.erase(s.getSecret());
m.clear();
}
public StreamContext getStreamContext(ContactId c,
=======
public synchronized boolean stop() {
eventBus.removeListener(this);
timer.cancel();
tagRecogniser.removeSecrets();
maxLatencies.clear();
oldSecrets.clear();
currentSecrets.clear();
newSecrets.clear();
return true;
}
public synchronized StreamContext getStreamContext(ContactId c,
>>>>>>> theSource
TransportId t) {
synchLock.lock();
try{
TemporarySecret s = currentSecrets.get(new EndpointKey(c, t));
if(s == null) {
LOG.info("No secret for endpoint");
return null;
}
long streamNumber;
try {
streamNumber = db.incrementStreamCounter(c, t, s.getPeriod());
if(streamNumber == -1) {
LOG.info("No counter for period");
return null;
}
} catch(DbException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null;
}
// Clone the secret - the original will be erased
byte[] secret = s.getSecret().clone();
return new StreamContext(c, t, secret, streamNumber, s.getAlice());
}
finally{
synchLock.unlock();
}
<<<<<<< HEAD
}
public void endpointAdded(Endpoint ep, long maxLatency,
byte[] initialSecret) {
synchLock.lock();
try{
maxLatencies.put(ep.getTransportId(), maxLatency);
// Work out which rotation period we're in
long elapsed = clock.currentTimeMillis() - ep.getEpoch();
long rotation = maxLatency + MAX_CLOCK_DIFFERENCE;
long period = (elapsed / rotation) + 1;
if(period < 1) throw new IllegalStateException();
// Derive the old, current and new secrets
byte[] b1 = initialSecret;
for(long p = 0; p < period; p++) {
byte[] temp = crypto.deriveNextSecret(b1, p);
ByteUtils.erase(b1);
b1 = temp;
}
byte[] b2 = crypto.deriveNextSecret(b1, period);
byte[] b3 = crypto.deriveNextSecret(b2, period + 1);
TemporarySecret s1 = new TemporarySecret(ep, period - 1, b1);
TemporarySecret s2 = new TemporarySecret(ep, period, b2);
TemporarySecret s3 = new TemporarySecret(ep, period + 1, b3);
// Add the incoming secrets to their respective maps
EndpointKey k = new EndpointKey(ep);
oldSecrets.put(k, s1);
currentSecrets.put(k, s2);
newSecrets.put(k, s3);
// Store the new secrets
try {
db.addSecrets(Arrays.asList(s1, s2, s3));
} catch(DbException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return;
}
// Pass the new secrets to the recogniser
tagRecogniser.addSecret(s1);
tagRecogniser.addSecret(s2);
tagRecogniser.addSecret(s3);
}
finally{
synchLock.unlock();
=======
byte[] secret = s.getSecret();
return new StreamContext(c, t, secret, streamNumber, s.getAlice());
}
public synchronized void endpointAdded(Endpoint ep, int maxLatency,
byte[] initialSecret) {
maxLatencies.put(ep.getTransportId(), maxLatency);
// Work out which rotation period we're in
long elapsed = clock.currentTimeMillis() - ep.getEpoch();
long rotation = maxLatency + MAX_CLOCK_DIFFERENCE;
long period = (elapsed / rotation) + 1;
if(period < 1) throw new IllegalStateException();
// Derive the old, current and new secrets
byte[] b1 = initialSecret;
for(long p = 0; p < period; p++)
b1 = crypto.deriveNextSecret(b1, p);
byte[] b2 = crypto.deriveNextSecret(b1, period);
byte[] b3 = crypto.deriveNextSecret(b2, period + 1);
TemporarySecret s1 = new TemporarySecret(ep, period - 1, b1);
TemporarySecret s2 = new TemporarySecret(ep, period, b2);
TemporarySecret s3 = new TemporarySecret(ep, period + 1, b3);
// Add the incoming secrets to their respective maps
EndpointKey k = new EndpointKey(ep);
oldSecrets.put(k, s1);
currentSecrets.put(k, s2);
newSecrets.put(k, s3);
// Store the new secrets
try {
db.addSecrets(Arrays.asList(s1, s2, s3));
} catch(DbException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return;
>>>>>>> theSource
}
}
@Override
public void run() {
synchLock.lock();
try{
// Rebuild the maps because we may be running a whole period late
Collection<TemporarySecret> secrets = new ArrayList<TemporarySecret>();
secrets.addAll(oldSecrets.values());
secrets.addAll(currentSecrets.values());
secrets.addAll(newSecrets.values());
oldSecrets.clear();
currentSecrets.clear();
newSecrets.clear();
// Work out what phase of its lifecycle each secret is in
long now = clock.currentTimeMillis();
Collection<TemporarySecret> dead = assignSecretsToMaps(now, secrets);
// Remove any dead secrets from the recogniser
for(TemporarySecret s : dead) {
ContactId c = s.getContactId();
TransportId t = s.getTransportId();
long period = s.getPeriod();
tagRecogniser.removeSecret(c, t, period);
}
// Replace any dead secrets
Collection<TemporarySecret> created = replaceDeadSecrets(now, dead);
if(!created.isEmpty()) {
// Store any secrets that have been created
try {
db.addSecrets(created);
} catch(DbException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
// Pass any secrets that have been created to the recogniser
for(TemporarySecret s : created) tagRecogniser.addSecret(s);
}
}
finally{
synchLock.unlock();
}
}
public void eventOccurred(Event e) {
if(e instanceof ContactRemovedEvent) {
ContactRemovedEvent c = (ContactRemovedEvent) e;
timer.schedule(new ContactRemovedTask(c), 0);
} else if(e instanceof TransportAddedEvent) {
TransportAddedEvent t = (TransportAddedEvent) e;
timer.schedule(new TransportAddedTask(t), 0);
} else if(e instanceof TransportRemovedEvent) {
TransportRemovedEvent t = (TransportRemovedEvent) e;
timer.schedule(new TransportRemovedTask(t), 0);
}
}
<<<<<<< HEAD
private void removeAndEraseSecrets(ContactId c, Map<?, TemporarySecret> m) {
=======
// Locking: this
private void removeSecrets(ContactId c, Map<?, TemporarySecret> m) {
>>>>>>> theSource
Iterator<TemporarySecret> it = m.values().iterator();
while(it.hasNext())
if(it.next().getContactId().equals(c)) it.remove();
}
<<<<<<< HEAD
private void removeAndEraseSecrets(TransportId t,
Map<?, TemporarySecret> m) {
=======
// Locking: this
private void removeSecrets(TransportId t, Map<?, TemporarySecret> m) {
>>>>>>> theSource
Iterator<TemporarySecret> it = m.values().iterator();
while(it.hasNext())
if(it.next().getTransportId().equals(t)) it.remove();
}
private static class EndpointKey {
private final ContactId contactId;
private final TransportId transportId;
private EndpointKey(ContactId contactId, TransportId transportId) {
this.contactId = contactId;
this.transportId = transportId;
}
private EndpointKey(Endpoint ep) {
this(ep.getContactId(), ep.getTransportId());
}
@Override
public int hashCode() {
return contactId.hashCode() ^ transportId.hashCode();
}
@Override
public boolean equals(Object o) {
if(o instanceof EndpointKey) {
EndpointKey k = (EndpointKey) o;
return contactId.equals(k.contactId) &&
transportId.equals(k.transportId);
}
return false;
}
}
private class ContactRemovedTask extends TimerTask {
private final ContactRemovedEvent event;
private ContactRemovedTask(ContactRemovedEvent event) {
this.event = event;
}
@Override
public void run() {
ContactId c = event.getContactId();
tagRecogniser.removeSecrets(c);
<<<<<<< HEAD
synchLock.lock();
try {
removeAndEraseSecrets(c, oldSecrets);
removeAndEraseSecrets(c, currentSecrets);
removeAndEraseSecrets(c, newSecrets);
=======
synchronized(KeyManagerImpl.this) {
removeSecrets(c, oldSecrets);
removeSecrets(c, currentSecrets);
removeSecrets(c, newSecrets);
>>>>>>> theSource
}
finally{
synchLock.unlock();
}
}
}
private class TransportAddedTask extends TimerTask {
private final TransportAddedEvent event;
private TransportAddedTask(TransportAddedEvent event) {
this.event = event;
}
@Override
public void run() {
synchLock.lock();
try {
maxLatencies.put(event.getTransportId(), event.getMaxLatency());
}
finally{
synchLock.unlock();
}
}
}
private class TransportRemovedTask extends TimerTask {
private TransportRemovedEvent event;
private TransportRemovedTask(TransportRemovedEvent event) {
this.event = event;
}
@Override
public void run() {
TransportId t = event.getTransportId();
tagRecogniser.removeSecrets(t);
synchLock.lock();
try {
maxLatencies.remove(t);
removeSecrets(t, oldSecrets);
removeSecrets(t, currentSecrets);
removeSecrets(t, newSecrets);
}
finally{
synchLock.unlock();
}
}
}
}

View File

@@ -20,11 +20,10 @@ class TagRecogniserImpl implements TagRecogniser {
private final CryptoComponent crypto;
private final DatabaseComponent db;
private final Map<TransportId, TransportTagRecogniser> recognisers;
private final Lock synchLock = new ReentrantLock();
// Locking: synchLock
private final Map<TransportId, TransportTagRecogniser> recognisers;
@Inject
TagRecogniserImpl(CryptoComponent crypto, DatabaseComponent db) {

View File

@@ -29,11 +29,12 @@ class TransportTagRecogniser {
private final CryptoComponent crypto;
private final DatabaseComponent db;
private final TransportId transportId;
private final Lock synchLock = new ReentrantLock();
// The following are locking: synchLock
private final Map<Bytes, TagContext> tagMap;
private final Map<RemovalKey, RemovalContext> removalMap;
private final Lock synchLock = new ReentrantLock();
TransportTagRecogniser(CryptoComponent crypto, DatabaseComponent db,
TransportId transportId) {
this.crypto = crypto;
@@ -112,6 +113,7 @@ class TransportTagRecogniser {
}
}
// Locking: synchLock
private void removeSecret(RemovalContext r) {
// Remove the expected tags
SecretKey key = crypto.deriveTagKey(r.secret, !r.alice);

View File

@@ -1,235 +0,0 @@
package org.briarproject.transport;
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.briarproject.api.Bytes;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.transport.StreamContext;
import org.briarproject.api.transport.TemporarySecret;
// FIXME: Don't make alien calls with a lock held
/**
* A {@link org.briarproject.api.transport.TagRecogniser TagRecogniser} for a
* specific transport.
*/
class TransportTagRecogniser {
private final CryptoComponent crypto;
private final DatabaseComponent db;
private final TransportId transportId;
private final Map<Bytes, TagContext> tagMap;
private final Map<RemovalKey, RemovalContext> removalMap;
private final Lock synchLock = new ReentrantLock();
TransportTagRecogniser(CryptoComponent crypto, DatabaseComponent db,
TransportId transportId) {
this.crypto = crypto;
this.db = db;
this.transportId = transportId;
tagMap = new HashMap<Bytes, TagContext>();
removalMap = new HashMap<RemovalKey, RemovalContext>();
}
StreamContext recogniseTag(byte[] tag) throws DbException {
synchLock.lock();
try{
TagContext t = tagMap.remove(new Bytes(tag));
if(t == null) return null; // The tag was not expected
// Update the reordering window and the expected tags
SecretKey key = crypto.deriveTagKey(t.secret, !t.alice);
for(long streamNumber : t.window.setSeen(t.streamNumber)) {
byte[] tag1 = new byte[TAG_LENGTH];
crypto.encodeTag(tag1, key, streamNumber);
if(streamNumber < t.streamNumber) {
TagContext removed = tagMap.remove(new Bytes(tag1));
assert removed != null;
} else {
TagContext added = new TagContext(t, streamNumber);
TagContext duplicate = tagMap.put(new Bytes(tag1), added);
assert duplicate == null;
}
}
key.erase();
// Store the updated reordering window in the DB
db.setReorderingWindow(t.contactId, transportId, t.period,
t.window.getCentre(), t.window.getBitmap());
// Clone the secret - the key manager will erase the original
byte[] secret = t.secret.clone();
return new StreamContext(t.contactId, transportId, secret,
t.streamNumber, t.alice);
}
finally{
synchLock.unlock();
}
<<<<<<< HEAD
=======
// Store the updated reordering window in the DB
db.setReorderingWindow(t.contactId, transportId, t.period,
t.window.getCentre(), t.window.getBitmap());
return new StreamContext(t.contactId, transportId, t.secret,
t.streamNumber, t.alice);
>>>>>>> theSource
}
void addSecret(TemporarySecret s) {
synchLock.lock();
try{
ContactId contactId = s.getContactId();
boolean alice = s.getAlice();
long period = s.getPeriod();
byte[] secret = s.getSecret();
long centre = s.getWindowCentre();
byte[] bitmap = s.getWindowBitmap();
// Create the reordering window and the expected tags
SecretKey key = crypto.deriveTagKey(secret, !alice);
ReorderingWindow window = new ReorderingWindow(centre, bitmap);
for(long streamNumber : window.getUnseen()) {
byte[] tag = new byte[TAG_LENGTH];
crypto.encodeTag(tag, key, streamNumber);
TagContext added = new TagContext(contactId, alice, period,
secret, window, streamNumber);
TagContext duplicate = tagMap.put(new Bytes(tag), added);
assert duplicate == null;
}
key.erase();
// Create a removal context to remove the window and the tags later
RemovalContext r = new RemovalContext(window, secret, alice);
removalMap.put(new RemovalKey(contactId, period), r);
}
finally{
synchLock.unlock();
}
<<<<<<< HEAD
=======
// Create a removal context to remove the window and the tags later
RemovalContext r = new RemovalContext(window, secret, alice);
removalMap.put(new RemovalKey(contactId, period), r);
>>>>>>> theSource
}
void removeSecret(ContactId contactId, long period) {
synchLock.lock();
try{
RemovalKey k = new RemovalKey(contactId, period);
RemovalContext removed = removalMap.remove(k);
if(removed == null) throw new IllegalArgumentException();
removeSecret(removed);
}
finally{
synchLock.unlock();
}
}
private void removeSecret(RemovalContext r) {
// Remove the expected tags
SecretKey key = crypto.deriveTagKey(r.secret, !r.alice);
byte[] tag = new byte[TAG_LENGTH];
for(long streamNumber : r.window.getUnseen()) {
crypto.encodeTag(tag, key, streamNumber);
TagContext removed = tagMap.remove(new Bytes(tag));
assert removed != null;
}
}
void removeSecrets(ContactId c) {
synchLock.lock();
try{
Collection<RemovalKey> keysToRemove = new ArrayList<RemovalKey>();
for(RemovalKey k : removalMap.keySet())
if(k.contactId.equals(c)) keysToRemove.add(k);
for(RemovalKey k : keysToRemove) removeSecret(k.contactId, k.period);
}
finally{
synchLock.unlock();
}
}
void removeSecrets() {
synchLock.lock();
try{
for(RemovalContext r : removalMap.values()) removeSecret(r);
assert tagMap.isEmpty();
removalMap.clear();
}
finally{
synchLock.unlock();
}
}
private static class TagContext {
private final ContactId contactId;
private final boolean alice;
private final long period;
private final byte[] secret;
private final ReorderingWindow window;
private final long streamNumber;
private TagContext(ContactId contactId, boolean alice, long period,
byte[] secret, ReorderingWindow window, long streamNumber) {
this.contactId = contactId;
this.alice = alice;
this.period = period;
this.secret = secret;
this.window = window;
this.streamNumber = streamNumber;
}
private TagContext(TagContext t, long streamNumber) {
this(t.contactId, t.alice, t.period, t.secret, t.window,
streamNumber);
}
}
private static class RemovalKey {
private final ContactId contactId;
private final long period;
private RemovalKey(ContactId contactId, long period) {
this.contactId = contactId;
this.period = period;
}
@Override
public int hashCode() {
return contactId.hashCode() ^ (int) (period ^ (period >>> 32));
}
@Override
public boolean equals(Object o) {
if(o instanceof RemovalKey) {
RemovalKey k = (RemovalKey) o;
return contactId.equals(k.contactId) && period == k.period;
}
return false;
}
}
private static class RemovalContext {
private final ReorderingWindow window;
private final byte[] secret;
private final boolean alice;
private RemovalContext(ReorderingWindow window, byte[] secret,
boolean alice) {
this.window = window;
this.secret = secret;
this.alice = alice;
}
}
}