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

@@ -61,18 +61,18 @@ Service, EventListener {
private final Executor dbExecutor; private final Executor dbExecutor;
private final EventBus eventBus; private final EventBus eventBus;
private final Context appContext; private final Context appContext;
private final Lock synchLock = new ReentrantLock();
// The following are locking: synchLock
private final Map<ContactId, Integer> contactCounts = private final Map<ContactId, Integer> contactCounts =
new HashMap<ContactId, Integer>(); new HashMap<ContactId, Integer>();
private final Map<GroupId, Integer> groupCounts = private final Map<GroupId, Integer> groupCounts =
new HashMap<GroupId, Integer>(); new HashMap<GroupId, Integer>();
private int privateTotal = 0, groupTotal = 0; private int privateTotal = 0, groupTotal = 0;
private int nextRequestId = 0; private int nextRequestId = 0;
private volatile Settings settings = new Settings(); private volatile Settings settings = new Settings();
private final Lock synchLock = new ReentrantLock();
@Inject @Inject
public AndroidNotificationManagerImpl(DatabaseComponent db, public AndroidNotificationManagerImpl(DatabaseComponent db,
@DatabaseExecutor Executor dbExecutor, EventBus eventBus, @DatabaseExecutor Executor dbExecutor, EventBus eventBus,
@@ -136,6 +136,7 @@ Service, EventListener {
} }
} }
// Locking: synchLock
private void updatePrivateMessageNotification() { private void updatePrivateMessageNotification() {
if(privateTotal == 0) { if(privateTotal == 0) {
clearPrivateMessageNotification(); clearPrivateMessageNotification();
@@ -180,6 +181,7 @@ Service, EventListener {
} }
} }
// Locking: synchLock
private void clearPrivateMessageNotification() { private void clearPrivateMessageNotification() {
Object o = appContext.getSystemService(NOTIFICATION_SERVICE); Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o; NotificationManager nm = (NotificationManager) o;
@@ -222,6 +224,7 @@ Service, EventListener {
} }
} }
// Locking: synchLock
private void updateGroupPostNotification() { private void updateGroupPostNotification() {
if(groupTotal == 0) { if(groupTotal == 0) {
clearGroupPostNotification(); clearGroupPostNotification();
@@ -266,6 +269,7 @@ Service, EventListener {
} }
} }
// Locking: synchLock
private void clearGroupPostNotification() { private void clearGroupPostNotification() {
Object o = appContext.getSystemService(NOTIFICATION_SERVICE); Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o; NotificationManager nm = (NotificationManager) o;

View File

@@ -15,13 +15,13 @@ class ReferenceManagerImpl implements ReferenceManager {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ReferenceManagerImpl.class.getName()); Logger.getLogger(ReferenceManagerImpl.class.getName());
private final Lock synchLock = new ReentrantLock();
// The following are locking: synchLock
private final Map<Class<?>, Map<Long, Object>> outerMap = private final Map<Class<?>, Map<Long, Object>> outerMap =
new HashMap<Class<?>, Map<Long, Object>>(); new HashMap<Class<?>, Map<Long, Object>>();
private long nextHandle = 0; private long nextHandle = 0;
private final Lock synchLock = new ReentrantLock();
public <T> T getReference(long handle, Class<T> c) { public <T> T getReference(long handle, Class<T> c) {
synchLock.lock(); synchLock.lock();
try { try {

View File

@@ -19,6 +19,9 @@ class FortunaGenerator {
private static final int KEY_BYTES = 32; private static final int KEY_BYTES = 32;
private static final int BLOCK_BYTES = 16; 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 MessageDigest digest = new DoubleDigest(new SHA256Digest());
private final BlockCipher cipher = new AESLightEngine(); private final BlockCipher cipher = new AESLightEngine();
private final byte[] key = new byte[KEY_BYTES]; 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[] buffer = new byte[BLOCK_BYTES];
private final byte[] newKey = new byte[KEY_BYTES]; private final byte[] newKey = new byte[KEY_BYTES];
private final Lock synchLock = new ReentrantLock();
FortunaGenerator(byte[] seed) { FortunaGenerator(byte[] seed) {
reseed(seed); reseed(seed);
} }

View File

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

View File

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

View File

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

View File

@@ -27,13 +27,12 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
Logger.getLogger(ConnectionRegistryImpl.class.getName()); Logger.getLogger(ConnectionRegistryImpl.class.getName());
private final EventBus eventBus; 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(); 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 @Inject
ConnectionRegistryImpl(EventBus eventBus) { ConnectionRegistryImpl(EventBus eventBus) {
this.eventBus = eventBus; this.eventBus = eventBus;

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,11 +38,9 @@ class WindowsShutdownManagerImpl extends ShutdownManagerImpl {
private static final int WS_MINIMIZE = 0x20000000; private static final int WS_MINIMIZE = 0x20000000;
private final Map<String, Object> options; private final Map<String, Object> options;
private boolean initialised = false;
private final Lock synchLock = new ReentrantLock(); private final Lock synchLock = new ReentrantLock();
private boolean initialised = false; // Locking: synchLock
WindowsShutdownManagerImpl() { WindowsShutdownManagerImpl() {
// Use the Unicode versions of Win32 API calls // Use the Unicode versions of Win32 API calls
@@ -68,6 +66,7 @@ class WindowsShutdownManagerImpl extends ShutdownManagerImpl {
return new StartOnce(r); return new StartOnce(r);
} }
// Locking: synchLock
private void initialise() { private void initialise() {
if(OsUtils.isWindows()) { if(OsUtils.isWindows()) {
new EventLoop().start(); new EventLoop().start();

View File

@@ -20,12 +20,11 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
private final RemovableDriveFinder finder; private final RemovableDriveFinder finder;
private final int pollingInterval; private final int pollingInterval;
private volatile boolean running = false;
private volatile Callback callback = null;
private final Lock pollingLock = new ReentrantLock(); private final Lock pollingLock = new ReentrantLock();
private final Condition stopPolling = pollingLock.newCondition(); private final Condition stopPolling = pollingLock.newCondition();
private volatile boolean running = false;
private volatile Callback callback = null;
public PollingRemovableDriveMonitor(Executor ioExecutor, public PollingRemovableDriveMonitor(Executor ioExecutor,
RemovableDriveFinder finder, int pollingInterval) { RemovableDriveFinder finder, int pollingInterval) {

View File

@@ -1,83 +0,0 @@
package org.briarproject.plugins.file;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
private static final Logger LOG =
Logger.getLogger(PollingRemovableDriveMonitor.class.getName());
private final Executor ioExecutor;
private final RemovableDriveFinder finder;
<<<<<<< HEAD
private final long pollingInterval;
=======
private final int pollingInterval;
private final Object pollingLock = new Object();
>>>>>>> theSource
private volatile boolean running = false;
private volatile Callback callback = null;
private final Lock pollingLock = new ReentrantLock();
private final Condition stopPolling = pollingLock.newCondition();
public PollingRemovableDriveMonitor(Executor ioExecutor,
RemovableDriveFinder finder, int pollingInterval) {
this.ioExecutor = ioExecutor;
this.finder = finder;
this.pollingInterval = pollingInterval;
}
public void start(Callback callback) throws IOException {
this.callback = callback;
running = true;
ioExecutor.execute(this);
}
public void stop() throws IOException {
running = false;
pollingLock.lock();
try {
stopPolling.signalAll();
}
finally {
pollingLock.unlock();
}
}
public void run() {
try {
Collection<File> drives = finder.findRemovableDrives();
while(running) {
pollingLock.lock();
try {
stopPolling.await(pollingInterval, TimeUnit.MILLISECONDS);
}
finally{
pollingLock.unlock();
}
if(!running) return;
Collection<File> newDrives = finder.findRemovableDrives();
for(File f : newDrives) {
if(!drives.contains(f)) callback.driveInserted(f);
}
drives = newDrives;
}
} catch(InterruptedException e) {
LOG.warning("Interrupted while waiting to poll");
Thread.currentThread().interrupt();
} catch(IOException e) {
callback.exceptionThrown(e);
}
}
}

View File

@@ -13,20 +13,22 @@ import net.contentobjects.jnotify.JNotifyListener;
abstract class UnixRemovableDriveMonitor implements RemovableDriveMonitor, abstract class UnixRemovableDriveMonitor implements RemovableDriveMonitor,
JNotifyListener { JNotifyListener {
//TODO: rationalise this in a further refactor
private static final Lock staticSynchLock = new ReentrantLock();
// The following are locking: staticSynchLock
private static boolean triedLoad = false; private static boolean triedLoad = false;
private static Throwable loadError = null; private static Throwable loadError = null;
private final List<Integer> watches = new ArrayList<Integer>(); private final Lock synchLock = new ReentrantLock();
// The following are locking: synchLock
private final List<Integer> watches = new ArrayList<Integer>();
private boolean started = false; private boolean started = false;
private Callback callback = null; private Callback callback = null;
protected abstract String[] getPathsToWatch(); protected abstract String[] getPathsToWatch();
//TODO: rationalise this in a further refactor
private final Lock synchLock = new ReentrantLock();
private static final Lock staticSynchLock = new ReentrantLock();
private static Throwable tryLoad() { private static Throwable tryLoad() {
try { try {
Class.forName("net.contentobjects.jnotify.JNotify"); Class.forName("net.contentobjects.jnotify.JNotify");

View File

@@ -91,161 +91,160 @@ class CountryCodes {
new Country("GP", "Guadeloupe", "590", "00", ""), new Country("GP", "Guadeloupe", "590", "00", ""),
new Country("GQ", "Equatorial Guinea", "240", "00", ""), new Country("GQ", "Equatorial Guinea", "240", "00", ""),
new Country("GR", "Greece", "30", "00", ""), new Country("GR", "Greece", "30", "00", ""),
new Country("GS", "South Georgia and the South Sandwich Islands", new Country("GS", "South Georgia and the South Sandwich Islands", "995", "8**10", "8"),
"995", "8**10", "8"), new Country("GT", "Guatemala", "502", "00", ""),
new Country("GT", "Guatemala", "502", "00", ""), new Country("GU", "Guam", "1", "011", "1"),
new Country("GU", "Guam", "1", "011", "1"), new Country("GW", "Guinea-Bissau", "245", "00", ""),
new Country("GW", "Guinea-Bissau", "245", "00", ""), new Country("GY", "Guyana", "592", "001", "0"),
new Country("GY", "Guyana", "592", "001", "0"), new Country("HK", "Hong Kong", "852", "001", ""),
new Country("HK", "Hong Kong", "852", "001", ""), new Country("HM", "Heard Island and McDonald Islands", "692", "00", "0"),
new Country("HM", "Heard Island and McDonald Islands", "692", "00", "0"), new Country("HN", "Honduras", "504", "00", "0"),
new Country("HN", "Honduras", "504", "00", "0"), new Country("HR", "Croatia", "385", "00", "0"),
new Country("HR", "Croatia", "385", "00", "0"), new Country("HT", "Haiti", "509", "00", "0"),
new Country("HT", "Haiti", "509", "00", "0"), new Country("HU", "Hungary", "36", "00", "06"),
new Country("HU", "Hungary", "36", "00", "06"), new Country("ID", "Indonesia", "62", "001", "0"),
new Country("ID", "Indonesia", "62", "001", "0"), new Country("IE", "Ireland", "353", "00", "0"),
new Country("IE", "Ireland", "353", "00", "0"), new Country("IL", "Israel", "972", "00", "0"),
new Country("IL", "Israel", "972", "00", "0"), new Country("IN", "India", "91", "00", "0"),
new Country("IN", "India", "91", "00", "0"), new Country("IO", "British Indian Ocean Territory", "246", "00", ""),
new Country("IO", "British Indian Ocean Territory", "246", "00", ""), new Country("IQ", "Iraq", "964", "00", "0"),
new Country("IQ", "Iraq", "964", "00", "0"), new Country("IR", "Iran", "98", "00", "0"),
new Country("IR", "Iran", "98", "00", "0"), new Country("IS", "Iceland", "354", "00", "0"),
new Country("IS", "Iceland", "354", "00", "0"), new Country("IT", "Italy", "39", "00", ""),
new Country("IT", "Italy", "39", "00", ""), new Country("JM", "Jamaica", "1", "011", "1"),
new Country("JM", "Jamaica", "1", "011", "1"), new Country("JO", "Jordan", "962", "00", "0"),
new Country("JO", "Jordan", "962", "00", "0"), new Country("JP", "Japan", "81", "001", "0"),
new Country("JP", "Japan", "81", "001", "0"), new Country("KE", "Kenya", "254", "000", "0"),
new Country("KE", "Kenya", "254", "000", "0"), new Country("KG", "Kyrgyzstan", "996", "00", "0"),
new Country("KG", "Kyrgyzstan", "996", "00", "0"), new Country("KH", "Cambodia", "855", "001", "0"),
new Country("KH", "Cambodia", "855", "001", "0"), new Country("KI", "Kiribati", "686", "00", "0"),
new Country("KI", "Kiribati", "686", "00", "0"), new Country("KM", "Comoros", "269", "00", ""),
new Country("KM", "Comoros", "269", "00", ""), new Country("KN", "Saint Kitts and Nevis", "1", "011", "1"),
new Country("KN", "Saint Kitts and Nevis", "1", "011", "1"), new Country("KP", "Korea (North)", "850", "00", "0"),
new Country("KP", "Korea (North)", "850", "00", "0"), new Country("KR", "Korea (South)", "82", "001", "0"),
new Country("KR", "Korea (South)", "82", "001", "0"), new Country("KW", "Kuwait", "965", "00", "0"),
new Country("KW", "Kuwait", "965", "00", "0"), new Country("KY", "Cayman Islands", "1", "011", "1"),
new Country("KY", "Cayman Islands", "1", "011", "1"), new Country("KZ", "Kazakhstan", "7", "8**10", "8"),
new Country("KZ", "Kazakhstan", "7", "8**10", "8"), new Country("LA", "Laos", "856", "00", "0"),
new Country("LA", "Laos", "856", "00", "0"), new Country("LB", "Lebanon", "961", "00", "0"),
new Country("LB", "Lebanon", "961", "00", "0"), new Country("LC", "Saint Lucia", "1", "011", "1"),
new Country("LC", "Saint Lucia", "1", "011", "1"), new Country("LI", "Liechtenstein", "423", "00", ""),
new Country("LI", "Liechtenstein", "423", "00", ""), new Country("LK", "Sri Lanka", "94", "00", "0"),
new Country("LK", "Sri Lanka", "94", "00", "0"), new Country("LR", "Liberia", "231", "00", "22"),
new Country("LR", "Liberia", "231", "00", "22"), new Country("LS", "Lesotho", "266", "00", "0"),
new Country("LS", "Lesotho", "266", "00", "0"), new Country("LT", "Lithuania", "370", "00", "8"),
new Country("LT", "Lithuania", "370", "00", "8"), new Country("LU", "Luxembourg", "352", "00", ""),
new Country("LU", "Luxembourg", "352", "00", ""), new Country("LV", "Latvia", "371", "00", "8"),
new Country("LV", "Latvia", "371", "00", "8"), new Country("LY", "Libya", "218", "00", "0"),
new Country("LY", "Libya", "218", "00", "0"), new Country("MA", "Morocco", "212", "00", ""),
new Country("MA", "Morocco", "212", "00", ""), new Country("MC", "Monaco", "377", "00", "0"),
new Country("MC", "Monaco", "377", "00", "0"), new Country("MD", "Moldova", "373", "00", "0"),
new Country("MD", "Moldova", "373", "00", "0"), new Country("ME", "Montenegro", "382", "99", "0"),
new Country("ME", "Montenegro", "382", "99", "0"), new Country("MG", "Madagascar", "261", "00", "0"),
new Country("MG", "Madagascar", "261", "00", "0"), new Country("MH", "Marshall Islands", "692", "011", "1"),
new Country("MH", "Marshall Islands", "692", "011", "1"), new Country("MK", "Macedonia", "389", "00", "0"),
new Country("MK", "Macedonia", "389", "00", "0"), new Country("ML", "Mali", "223", "00", "0"),
new Country("ML", "Mali", "223", "00", "0"), new Country("MM", "Myanmar", "95", "00", ""),
new Country("MM", "Myanmar", "95", "00", ""), new Country("MN", "Mongolia", "976", "001", "0"),
new Country("MN", "Mongolia", "976", "001", "0"), new Country("MO", "Macao", "853", "00", "0"),
new Country("MO", "Macao", "853", "00", "0"), new Country("MP", "Northern Mariana Islands", "1", "011", "1"),
new Country("MP", "Northern Mariana Islands", "1", "011", "1"), new Country("MQ", "Martinique", "596", "00", "0"),
new Country("MQ", "Martinique", "596", "00", "0"), new Country("MR", "Mauritania", "222", "00", "0"),
new Country("MR", "Mauritania", "222", "00", "0"), new Country("MS", "Montserrat", "1", "011", "1"),
new Country("MS", "Montserrat", "1", "011", "1"), new Country("MT", "Malta", "356", "00", "21"),
new Country("MT", "Malta", "356", "00", "21"), new Country("MU", "Mauritius", "230", "00", "0"),
new Country("MU", "Mauritius", "230", "00", "0"), new Country("MV", "Maldives", "960", "00", "0"),
new Country("MV", "Maldives", "960", "00", "0"), new Country("MW", "Malawi", "265", "00", ""),
new Country("MW", "Malawi", "265", "00", ""), new Country("MX", "Mexico", "52", "00", "01"),
new Country("MX", "Mexico", "52", "00", "01"), new Country("MY", "Malaysia", "60", "00", "0"),
new Country("MY", "Malaysia", "60", "00", "0"), new Country("MZ", "Mozambique", "258", "00", "0"),
new Country("MZ", "Mozambique", "258", "00", "0"), new Country("NA", "Namibia", "264", "00", "0"),
new Country("NA", "Namibia", "264", "00", "0"), new Country("NC", "New Caledonia", "687", "00", "0"),
new Country("NC", "New Caledonia", "687", "00", "0"), new Country("NE", "Niger", "227", "00", "0"),
new Country("NE", "Niger", "227", "00", "0"), new Country("NF", "Norfolk Island", "672", "00", ""),
new Country("NF", "Norfolk Island", "672", "00", ""), new Country("NG", "Nigeria", "234", "009", "0"),
new Country("NG", "Nigeria", "234", "009", "0"), new Country("NI", "Nicaragua", "505", "00", "0"),
new Country("NI", "Nicaragua", "505", "00", "0"), new Country("NL", "Netherlands", "31", "00", "0"),
new Country("NL", "Netherlands", "31", "00", "0"), new Country("NO", "Norway", "47", "00", ""),
new Country("NO", "Norway", "47", "00", ""), new Country("NP", "Nepal", "977", "00", "0"),
new Country("NP", "Nepal", "977", "00", "0"), new Country("NR", "Nauru", "674", "00", "0"),
new Country("NR", "Nauru", "674", "00", "0"), new Country("NU", "Niue", "683", "00", "0"),
new Country("NU", "Niue", "683", "00", "0"), new Country("NZ", "New Zealand", "64", "00", "0"),
new Country("NZ", "New Zealand", "64", "00", "0"), new Country("OM", "Oman", "968", "00", "0"),
new Country("OM", "Oman", "968", "00", "0"), new Country("PA", "Panama", "507", "00", "0"),
new Country("PA", "Panama", "507", "00", "0"), new Country("PE", "Peru", "51", "00", "0"),
new Country("PE", "Peru", "51", "00", "0"), new Country("PF", "French Polynesia", "689", "00", ""),
new Country("PF", "French Polynesia", "689", "00", ""), new Country("PG", "Papua New Guinea", "675", "05", ""),
new Country("PG", "Papua New Guinea", "675", "05", ""), new Country("PH", "Philippines", "63", "00", "0"),
new Country("PH", "Philippines", "63", "00", "0"), new Country("PK", "Pakistan", "92", "00", "0"),
new Country("PK", "Pakistan", "92", "00", "0"), new Country("PL", "Poland", "48", "00", "0"),
new Country("PL", "Poland", "48", "00", "0"), new Country("PM", "Saint Pierre and Miquelon", "508", "00", "0"),
new Country("PM", "Saint Pierre and Miquelon", "508", "00", "0"), new Country("PN", "Pitcairn", "872", "", ""),
new Country("PN", "Pitcairn", "872", "", ""), new Country("PR", "Puerto Rico", "1", "011", "1"),
new Country("PR", "Puerto Rico", "1", "011", "1"), new Country("PS", "Palestine", "970", "00", "0"),
new Country("PS", "Palestine", "970", "00", "0"), new Country("PT", "Portugal", "351", "00", ""),
new Country("PT", "Portugal", "351", "00", ""), new Country("PW", "Palau", "680", "011", ""),
new Country("PW", "Palau", "680", "011", ""), new Country("PY", "Paraguay", "595", "002", "0"),
new Country("PY", "Paraguay", "595", "002", "0"), new Country("QA", "Qatar", "974", "00", "0"),
new Country("QA", "Qatar", "974", "00", "0"), new Country("RE", "Reunion", "262", "00", "0"),
new Country("RE", "Reunion", "262", "00", "0"), new Country("RO", "Romania", "40", "00", "0"),
new Country("RO", "Romania", "40", "00", "0"), new Country("RS", "Serbia", "381", "99", "0"),
new Country("RS", "Serbia", "381", "99", "0"), new Country("RU", "Russia", "7", "8**10", "8"),
new Country("RU", "Russia", "7", "8**10", "8"), new Country("RW", "Rwanda", "250", "00", "0"),
new Country("RW", "Rwanda", "250", "00", "0"), new Country("SA", "Saudi Arabia", "966", "00", "0"),
new Country("SA", "Saudi Arabia", "966", "00", "0"), new Country("SB", "Solomon Islands", "677", "00", ""),
new Country("SB", "Solomon Islands", "677", "00", ""), new Country("SC", "Seychelles", "248", "00", "0"),
new Country("SC", "Seychelles", "248", "00", "0"), new Country("SD", "Sudan", "249", "00", "0"),
new Country("SD", "Sudan", "249", "00", "0"), new Country("SE", "Sweden", "46", "00", "0"),
new Country("SE", "Sweden", "46", "00", "0"), new Country("SG", "Singapore", "65", "001", ""),
new Country("SG", "Singapore", "65", "001", ""), new Country("SH", "Saint Helena", "290", "00", ""),
new Country("SH", "Saint Helena", "290", "00", ""), new Country("SI", "Slovenia", "386", "00", "0"),
new Country("SI", "Slovenia", "386", "00", "0"), new Country("SJ", "Svalbard and Jan Mayen", "378", "00", "0"),
new Country("SJ", "Svalbard and Jan Mayen", "378", "00", "0"), new Country("SK", "Slovakia", "421", "00", "0"),
new Country("SK", "Slovakia", "421", "00", "0"), new Country("SL", "Sierra Leone", "232", "00", "0"),
new Country("SL", "Sierra Leone", "232", "00", "0"), new Country("SM", "San Marino", "378", "00", "0"),
new Country("SM", "San Marino", "378", "00", "0"), new Country("SN", "Senegal", "221", "00", "0"),
new Country("SN", "Senegal", "221", "00", "0"), new Country("SO", "Somalia", "252", "00", ""),
new Country("SO", "Somalia", "252", "00", ""), new Country("SR", "Suriname", "597", "00", ""),
new Country("SR", "Suriname", "597", "00", ""), new Country("ST", "Sao Tome and Principe", "239", "00", "0"),
new Country("ST", "Sao Tome and Principe", "239", "00", "0"), new Country("SV", "El Salvador", "503", "00", ""),
new Country("SV", "El Salvador", "503", "00", ""), new Country("SY", "Syria", "963", "00", "0"),
new Country("SY", "Syria", "963", "00", "0"), new Country("SZ", "Swaziland", "268", "00", ""),
new Country("SZ", "Swaziland", "268", "00", ""), new Country("TC", "Turks and Caicos Islands", "1", "011", "1"),
new Country("TC", "Turks and Caicos Islands", "1", "011", "1"), new Country("TD", "Chad", "235", "15", ""),
new Country("TD", "Chad", "235", "15", ""), new Country("TF", "French Southern Territories", "596", "00", "0"),
new Country("TF", "French Southern Territories", "596", "00", "0"), new Country("TG", "Togo", "228", "00", ""),
new Country("TG", "Togo", "228", "00", ""), new Country("TH", "Thailand", "66", "001", "0"),
new Country("TH", "Thailand", "66", "001", "0"), new Country("TJ", "Tajikistan", "992", "8**10", "8"),
new Country("TJ", "Tajikistan", "992", "8**10", "8"), new Country("TK", "Tokelau", "690", "00", ""),
new Country("TK", "Tokelau", "690", "00", ""), new Country("TL", "Timor-Leste", "670", "00", ""),
new Country("TL", "Timor-Leste", "670", "00", ""), new Country("TM", "Turkmenistan", "993", "8**10", "8"),
new Country("TM", "Turkmenistan", "993", "8**10", "8"), new Country("TN", "Tunisia", "216", "00", "0"),
new Country("TN", "Tunisia", "216", "00", "0"), new Country("TO", "Tonga Islands", "676", "00", ""),
new Country("TO", "Tonga Islands", "676", "00", ""), new Country("TR", "Turkey", "90", "00", "0"),
new Country("TR", "Turkey", "90", "00", "0"), new Country("TT", "Trinidad and Tobago", "1", "011", "1"),
new Country("TT", "Trinidad and Tobago", "1", "011", "1"), new Country("TV", "Tuvalu", "688", "00", ""),
new Country("TV", "Tuvalu", "688", "00", ""), new Country("TW", "Taiwan", "886", "002", ""),
new Country("TW", "Taiwan", "886", "002", ""), new Country("TZ", "Tanzania", "255", "000", "0"),
new Country("TZ", "Tanzania", "255", "000", "0"), new Country("UA", "Ukraine", "380", "8**10", "8"),
new Country("UA", "Ukraine", "380", "8**10", "8"), new Country("UG", "Uganda", "256", "000", "0"),
new Country("UG", "Uganda", "256", "000", "0"), new Country("US", "United States", "1", "011", "1"),
new Country("US", "United States", "1", "011", "1"), new Country("UY", "Uruguay", "598", "00", "0"),
new Country("UY", "Uruguay", "598", "00", "0"), new Country("UZ", "Uzbekistan", "998", "8**10", "8"),
new Country("UZ", "Uzbekistan", "998", "8**10", "8"), new Country("VA", "Holy See (Vatican City State)", "379", "00", ""),
new Country("VA", "Holy See (Vatican City State)", "379", "00", ""), new Country("VC", "Saint Vincent and the Grenadines", "1", "011", "1"),
new Country("VC", "Saint Vincent and the Grenadines", "1", "011", "1"), new Country("VE", "Venezuela", "58", "00", "0"),
new Country("VE", "Venezuela", "58", "00", "0"), new Country("VG", "Virgin Islands (British)", "1", "011", "1"),
new Country("VG", "Virgin Islands (British)", "1", "011", "1"), new Country("VI", "Virgin Islands (U.S.)", "1", "011", "1"),
new Country("VI", "Virgin Islands (U.S.)", "1", "011", "1"), new Country("VN", "Viet Nam", "84", "00", "0"),
new Country("VN", "Viet Nam", "84", "00", "0"), new Country("VU", "Vanuatu", "678", "00", ""),
new Country("VU", "Vanuatu", "678", "00", ""), new Country("WF", "Wallis and Futuna Islands", "681", "19", ""),
new Country("WF", "Wallis and Futuna Islands", "681", "19", ""), new Country("WS", "Samoa (Western)", "685", "0", "0"),
new Country("WS", "Samoa (Western)", "685", "0", "0"), new Country("YE", "Yemen", "967", "00", "0"),
new Country("YE", "Yemen", "967", "00", "0"), new Country("YT", "Mayotte", "269", "00", ""),
new Country("YT", "Mayotte", "269", "00", ""), new Country("ZA", "South Africa", "27", "09", "0"),
new Country("ZA", "South Africa", "27", "09", "0"), new Country("ZM", "Zambia", "260", "00", "0"),
new Country("ZM", "Zambia", "260", "00", "0"), new Country("ZW", "Zimbabwe", "263", "110", "0")
new Country("ZW", "Zimbabwe", "263", "110", "0")
}; };
private static final Map<String, Country> COUNTRY_MAP = private static final Map<String, Country> COUNTRY_MAP =

View File

@@ -44,15 +44,15 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
private final Semaphore stateChange; private final Semaphore stateChange;
private final byte[] line; private final byte[] line;
private int lineLen = 0;
private ReliabilityLayer reliability = null;
private boolean initialised = false, connected = false;
private final Lock synchLock = new ReentrantLock(); private final Lock synchLock = new ReentrantLock();
private final Condition connectedStateChanged = synchLock.newCondition(); private final Condition connectedStateChanged = synchLock.newCondition();
private final Condition initialisedStateChanged = synchLock.newCondition(); private final Condition initialisedStateChanged = synchLock.newCondition();
// The following are locking: synchLock
private ReliabilityLayer reliability = null;
private boolean initialised = false, connected = false;
private int lineLen = 0;
ModemImpl(Executor ioExecutor, ReliabilityLayerFactory reliabilityFactory, ModemImpl(Executor ioExecutor, ReliabilityLayerFactory reliabilityFactory,
Clock clock, Callback callback, SerialPort port) { Clock clock, Callback callback, SerialPort port) {
@@ -161,6 +161,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
} }
} }
// Locking: stateChange
private void hangUpInner() throws IOException { private void hangUpInner() throws IOException {
ReliabilityLayer reliability; ReliabilityLayer reliability;
synchLock.lock(); synchLock.lock();

View File

@@ -213,9 +213,9 @@ public class StreamEncrypterImplTest extends BriarTestCase {
FrameEncoder.encodeHeader(header1, true, payloadLength1, FrameEncoder.encodeHeader(header1, true, payloadLength1,
paddingLength1); paddingLength1);
byte[] expected = new byte[HEADER_LENGTH + payloadLength byte[] expected = new byte[HEADER_LENGTH + payloadLength
+ paddingLength + MAC_LENGTH + paddingLength + MAC_LENGTH + HEADER_LENGTH
+ HEADER_LENGTH + payloadLength1 + payloadLength + paddingLength1
+ paddingLength1 + MAC_LENGTH]; + MAC_LENGTH];
System.arraycopy(header, 0, expected, 0, HEADER_LENGTH); System.arraycopy(header, 0, expected, 0, HEADER_LENGTH);
System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength); System.arraycopy(payload, 0, expected, HEADER_LENGTH, payloadLength);
System.arraycopy(header1, 0, expected, HEADER_LENGTH + payloadLength System.arraycopy(header1, 0, expected, HEADER_LENGTH + payloadLength