Wrapped System.currentTimeMillis() and Thread.sleep() for testability.

This commit is contained in:
akwizgran
2012-12-15 04:58:35 +00:00
parent 61e59f816d
commit 3e2e7286fe
26 changed files with 146 additions and 77 deletions

View File

@@ -8,4 +8,7 @@ public interface Clock {
/** @see {@link java.lang.System#currentTimeMillis()} */
long currentTimeMillis();
/** @see {@link java.lang.Thread.sleep(long)} */
void sleep(long milliseconds) throws InterruptedException;
}

View File

@@ -6,4 +6,8 @@ public class SystemClock implements Clock {
public long currentTimeMillis() {
return System.currentTimeMillis();
}
public void sleep(long milliseconds) throws InterruptedException {
Thread.sleep(milliseconds);
}
}

View File

@@ -10,6 +10,7 @@ import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.util.logging.Logger;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
@@ -25,16 +26,16 @@ class AliceConnector extends Connector {
Logger.getLogger(AliceConnector.class.getName());
AliceConnector(CryptoComponent crypto, ReaderFactory readerFactory,
WriterFactory writerFactory, ConnectorGroup group,
WriterFactory writerFactory, Clock clock, ConnectorGroup group,
DuplexPlugin plugin, int localCode, int remoteCode) {
super(crypto, readerFactory, writerFactory, group, plugin,
super(crypto, readerFactory, writerFactory, clock, group, plugin,
crypto.getPseudoRandom(localCode, remoteCode));
}
@Override
public void run() {
// Try an outgoing connection first, then an incoming connection
long halfTime = System.currentTimeMillis() + CONNECTION_TIMEOUT;
long halfTime = clock.currentTimeMillis() + CONNECTION_TIMEOUT;
DuplexTransportConnection conn = makeOutgoingConnection();
if(conn == null) {
waitForHalfTime(halfTime);

View File

@@ -10,6 +10,7 @@ import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.util.logging.Logger;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
@@ -25,16 +26,16 @@ class BobConnector extends Connector {
Logger.getLogger(BobConnector.class.getName());
BobConnector(CryptoComponent crypto, ReaderFactory readerFactory,
WriterFactory writerFactory, ConnectorGroup group,
WriterFactory writerFactory, Clock clock, ConnectorGroup group,
DuplexPlugin plugin, int localCode, int remoteCode) {
super(crypto, readerFactory, writerFactory, group, plugin,
super(crypto, readerFactory, writerFactory, clock, group, plugin,
crypto.getPseudoRandom(remoteCode, localCode));
}
@Override
public void run() {
// Try an incoming connection first, then an outgoing connection
long halfTime = System.currentTimeMillis() + CONNECTION_TIMEOUT;
long halfTime = clock.currentTimeMillis() + CONNECTION_TIMEOUT;
DuplexTransportConnection conn = acceptIncomingConnection();
if(conn == null) {
waitForHalfTime(halfTime);

View File

@@ -2,8 +2,8 @@ package net.sf.briar.invitation;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.api.plugins.InvitationConstants.HASH_LENGTH;
import static net.sf.briar.api.plugins.InvitationConstants.CONNECTION_TIMEOUT;
import static net.sf.briar.api.plugins.InvitationConstants.HASH_LENGTH;
import static net.sf.briar.api.plugins.InvitationConstants.MAX_PUBLIC_KEY_LENGTH;
import java.io.IOException;
@@ -13,6 +13,7 @@ import java.util.Arrays;
import java.util.logging.Logger;
import net.sf.briar.api.FormatException;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.KeyParser;
import net.sf.briar.api.crypto.MessageDigest;
@@ -32,6 +33,7 @@ abstract class Connector extends Thread {
protected final CryptoComponent crypto;
protected final ReaderFactory readerFactory;
protected final WriterFactory writerFactory;
protected final Clock clock;
protected final ConnectorGroup group;
protected final DuplexPlugin plugin;
protected final PseudoRandom random;
@@ -42,12 +44,13 @@ abstract class Connector extends Thread {
private final MessageDigest messageDigest;
Connector(CryptoComponent crypto, ReaderFactory readerFactory,
WriterFactory writerFactory, ConnectorGroup group,
WriterFactory writerFactory, Clock clock, ConnectorGroup group,
DuplexPlugin plugin, PseudoRandom random) {
super("Connector");
this.crypto = crypto;
this.readerFactory = readerFactory;
this.writerFactory = writerFactory;
this.clock = clock;
this.group = group;
this.plugin = plugin;
this.random = random;
@@ -70,12 +73,12 @@ abstract class Connector extends Thread {
}
protected void waitForHalfTime(long halfTime) {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
if(now < halfTime) {
if(LOG.isLoggable(INFO))
LOG.info(pluginName + " sleeping until half-time");
try {
Thread.sleep(halfTime - now);
clock.sleep(halfTime - now);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO)) LOG.info("Interrupted while sleeping");
Thread.currentThread().interrupt();

View File

@@ -11,6 +11,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.invitation.InvitationListener;
import net.sf.briar.api.invitation.InvitationManager;
@@ -31,6 +32,7 @@ class ConnectorGroup extends Thread implements InvitationTask {
private final CryptoComponent crypto;
private final ReaderFactory readerFactory;
private final WriterFactory writerFactory;
private final Clock clock;
private final PluginManager pluginManager;
private final int handle, localInvitationCode, remoteInvitationCode;
private final Collection<InvitationListener> listeners;
@@ -50,13 +52,14 @@ class ConnectorGroup extends Thread implements InvitationTask {
ConnectorGroup(InvitationManager invitationManager, CryptoComponent crypto,
ReaderFactory readerFactory, WriterFactory writerFactory,
PluginManager pluginManager, int handle, int localInvitationCode,
int remoteInvitationCode) {
Clock clock, PluginManager pluginManager, int handle,
int localInvitationCode, int remoteInvitationCode) {
super("ConnectorGroup");
this.invitationManager = invitationManager;
this.crypto = crypto;
this.readerFactory = readerFactory;
this.writerFactory = writerFactory;
this.clock = clock;
this.pluginManager = pluginManager;
this.handle = handle;
this.localInvitationCode = localInvitationCode;
@@ -95,7 +98,7 @@ class ConnectorGroup extends Thread implements InvitationTask {
if(localInvitationCode < remoteInvitationCode) {
for(DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
Connector c = new AliceConnector(crypto, readerFactory,
writerFactory, this, plugin, localInvitationCode,
writerFactory, clock, this, plugin, localInvitationCode,
remoteInvitationCode);
connectors.add(c);
c.start();
@@ -103,7 +106,7 @@ class ConnectorGroup extends Thread implements InvitationTask {
} else {
for(DuplexPlugin plugin: pluginManager.getInvitationPlugins()) {
Connector c = (new BobConnector(crypto, readerFactory,
writerFactory, this, plugin, localInvitationCode,
writerFactory, clock, this, plugin, localInvitationCode,
remoteInvitationCode));
connectors.add(c);
c.start();

View File

@@ -4,6 +4,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.invitation.InvitationManager;
import net.sf.briar.api.invitation.InvitationTask;
@@ -18,6 +19,7 @@ class InvitationManagerImpl implements InvitationManager {
private final CryptoComponent crypto;
private final ReaderFactory readerFactory;
private final WriterFactory writerFactory;
private final Clock clock;
private final PluginManager pluginManager;
private final AtomicInteger nextHandle;
@@ -25,10 +27,12 @@ class InvitationManagerImpl implements InvitationManager {
@Inject
InvitationManagerImpl(CryptoComponent crypto, ReaderFactory readerFactory,
WriterFactory writerFactory, PluginManager pluginManager) {
WriterFactory writerFactory, Clock clock,
PluginManager pluginManager) {
this.crypto = crypto;
this.readerFactory = readerFactory;
this.writerFactory = writerFactory;
this.clock = clock;
this.pluginManager = pluginManager;
nextHandle = new AtomicInteger(0);
tasks = new ConcurrentHashMap<Integer, InvitationTask>();
@@ -37,7 +41,7 @@ class InvitationManagerImpl implements InvitationManager {
public InvitationTask createTask(int localCode, int remoteCode) {
int handle = nextHandle.incrementAndGet();
return new ConnectorGroup(this, crypto, readerFactory, writerFactory,
pluginManager, handle, localCode, remoteCode);
clock, pluginManager, handle, localCode, remoteCode);
}
public InvitationTask getTask(int handle) {

View File

@@ -9,6 +9,7 @@ import java.util.concurrent.ExecutorService;
import java.util.logging.Logger;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.plugins.Plugin;
import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.transport.ConnectionRegistry;
@@ -22,13 +23,15 @@ class PollerImpl implements Poller, Runnable {
private final ExecutorService pluginExecutor;
private final ConnectionRegistry connRegistry;
private final Clock clock;
private final SortedSet<PollTime> pollTimes;
@Inject
PollerImpl(@PluginExecutor ExecutorService pluginExecutor,
ConnectionRegistry connRegistry) {
ConnectionRegistry connRegistry, Clock clock) {
this.pluginExecutor = pluginExecutor;
this.connRegistry = connRegistry;
this.clock = clock;
pollTimes = new TreeSet<PollTime>();
}
@@ -39,7 +42,7 @@ class PollerImpl implements Poller, Runnable {
private synchronized void schedule(Plugin plugin) {
if(plugin.shouldPoll()) {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
long interval = plugin.getPollingInterval();
pollTimes.add(new PollTime(now + interval, plugin));
}
@@ -57,7 +60,7 @@ class PollerImpl implements Poller, Runnable {
if(LOG.isLoggable(INFO)) LOG.info("Finished polling");
return;
}
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
final PollTime p = pollTimes.first();
if(now >= p.time) {
boolean removed = pollTimes.remove(p);

View File

@@ -2,6 +2,7 @@ package net.sf.briar.plugins.bluetooth;
import java.util.concurrent.Executor;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.clock.SystemClock;
import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
@@ -14,9 +15,11 @@ public class BluetoothPluginFactory implements DuplexPluginFactory {
private static final long POLLING_INTERVAL = 3L * 60L * 1000L; // 3 mins
private final Executor pluginExecutor;
private final Clock clock;
public BluetoothPluginFactory(@PluginExecutor Executor pluginExecutor) {
this.pluginExecutor = pluginExecutor;
clock = new SystemClock();
}
public TransportId getId() {
@@ -24,7 +27,7 @@ public class BluetoothPluginFactory implements DuplexPluginFactory {
}
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
return new BluetoothPlugin(pluginExecutor, new SystemClock(), callback,
return new BluetoothPlugin(pluginExecutor, clock, callback,
POLLING_INTERVAL);
}
}

View File

@@ -2,20 +2,25 @@ package net.sf.briar.plugins.modem;
import java.util.concurrent.Executor;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.clock.SystemClock;
import net.sf.briar.api.reliability.ReliabilityLayerFactory;
class ModemFactoryImpl implements ModemFactory {
private final Executor executor;
private final ReliabilityLayerFactory reliabilityFactory;
private final Clock clock;
ModemFactoryImpl(Executor executor,
ReliabilityLayerFactory reliabilityFactory) {
this.executor = executor;
this.reliabilityFactory = reliabilityFactory;
clock = new SystemClock();
}
public Modem createModem(Modem.Callback callback, String portName) {
return new ModemImpl(executor, reliabilityFactory, callback, portName);
return new ModemImpl(executor, reliabilityFactory, clock, callback,
portName);
}
}

View File

@@ -12,14 +12,14 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore;
import java.util.logging.Logger;
import net.sf.briar.api.reliability.ReliabilityLayer;
import net.sf.briar.api.reliability.ReliabilityLayerFactory;
import net.sf.briar.api.reliability.WriteHandler;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.reliability.ReliabilityLayer;
import net.sf.briar.api.reliability.ReliabilityLayerFactory;
import net.sf.briar.api.reliability.WriteHandler;
class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
@@ -35,6 +35,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
private final Executor executor;
private final ReliabilityLayerFactory reliabilityFactory;
private final Clock clock;
private final Callback callback;
private final SerialPort port;
private final Semaphore stateChange;
@@ -46,9 +47,10 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
private boolean initialised = false, connected = false; // Locking: this
ModemImpl(Executor executor, ReliabilityLayerFactory reliabilityFactory,
Callback callback, String portName) {
Clock clock, Callback callback, String portName) {
this.executor = executor;
this.reliabilityFactory = reliabilityFactory;
this.clock = clock;
this.callback = callback;
port = new SerialPort(portName);
stateChange = new Semaphore(1);
@@ -96,11 +98,11 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
boolean success = false;
try {
synchronized(this) {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
long end = now + OK_TIMEOUT;
while(now < end && !initialised) {
wait(end - now);
now = System.currentTimeMillis();
now = clock.currentTimeMillis();
}
success = initialised;
}
@@ -169,9 +171,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
reliability.stop();
if(LOG.isLoggable(INFO)) LOG.info("Hanging up");
try {
Thread.sleep(ESCAPE_SEQUENCE_GUARD_TIME);
clock.sleep(ESCAPE_SEQUENCE_GUARD_TIME);
port.writeBytes("+++".getBytes("US-ASCII"));
Thread.sleep(ESCAPE_SEQUENCE_GUARD_TIME);
clock.sleep(ESCAPE_SEQUENCE_GUARD_TIME);
port.writeBytes("ATH\r\n".getBytes("US-ASCII"));
} catch(InterruptedException e) {
tryToClose(port);
@@ -217,11 +219,11 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
// Wait for the event thread to receive "CONNECT"
try {
synchronized(this) {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
long end = now + CONNECT_TIMEOUT;
while(now < end && initialised && !connected) {
wait(end - now);
now = System.currentTimeMillis();
now = clock.currentTimeMillis();
}
if(connected) return true;
}
@@ -397,11 +399,11 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
boolean success = false;
try {
synchronized(this) {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
long end = now + CONNECT_TIMEOUT;
while(now < end && initialised && !connected) {
wait(end - now);
now = System.currentTimeMillis();
now = clock.currentTimeMillis();
}
success = connected;
}

View File

@@ -22,6 +22,7 @@ import java.util.concurrent.Executor;
import java.util.logging.Logger;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.crypto.PseudoRandom;
import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
@@ -42,9 +43,12 @@ class LanTcpPlugin extends TcpPlugin {
private static final Logger LOG =
Logger.getLogger(LanTcpPlugin.class.getName());
LanTcpPlugin(@PluginExecutor Executor pluginExecutor,
private final Clock clock;
LanTcpPlugin(@PluginExecutor Executor pluginExecutor, Clock clock,
DuplexPluginCallback callback, long pollingInterval) {
super(pluginExecutor, callback, pollingInterval);
this.clock = clock;
}
public TransportId getId() {
@@ -130,7 +134,7 @@ class LanTcpPlugin extends TcpPlugin {
// Listen until a valid packet is received or the timeout occurs
byte[] buffer = new byte[2];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
long end = now + timeout;
try {
while(now < end) {
@@ -155,7 +159,7 @@ class LanTcpPlugin extends TcpPlugin {
} catch(SocketTimeoutException e) {
break;
}
now = System.currentTimeMillis();
now = clock.currentTimeMillis();
if(!running) return null;
}
if(LOG.isLoggable(INFO))
@@ -273,7 +277,7 @@ class LanTcpPlugin extends TcpPlugin {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
packet.setAddress(mcast.getAddress());
packet.setPort(mcast.getPort());
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
long end = now + timeout;
long interval = 1000;
long nextPacket = now + 1;
@@ -286,10 +290,10 @@ class LanTcpPlugin extends TcpPlugin {
s.setSoTimeout(0);
return new TcpTransportConnection(s);
} catch(SocketTimeoutException e) {
now = System.currentTimeMillis();
now = clock.currentTimeMillis();
if(now < end) {
ms.send(packet);
now = System.currentTimeMillis();
now = clock.currentTimeMillis();
nextPacket = now + interval;
interval += 1000;
}

View File

@@ -2,6 +2,8 @@ package net.sf.briar.plugins.tcp;
import java.util.concurrent.Executor;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.clock.SystemClock;
import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
@@ -13,9 +15,11 @@ public class LanTcpPluginFactory implements DuplexPluginFactory {
private static final long POLLING_INTERVAL = 60L * 1000L; // 1 minute
private final Executor pluginExecutor;
private final Clock clock;
public LanTcpPluginFactory(@PluginExecutor Executor pluginExecutor) {
this.pluginExecutor = pluginExecutor;
clock = new SystemClock();
}
public TransportId getId() {
@@ -23,6 +27,7 @@ public class LanTcpPluginFactory implements DuplexPluginFactory {
}
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
return new LanTcpPlugin(pluginExecutor, callback, POLLING_INTERVAL);
return new LanTcpPlugin(pluginExecutor, clock, callback,
POLLING_INTERVAL);
}
}

View File

@@ -13,6 +13,7 @@ import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.protocol.Author;
@@ -38,14 +39,17 @@ class MessageFactoryImpl implements MessageFactory {
private final SecureRandom random;
private final MessageDigest messageDigest;
private final WriterFactory writerFactory;
private final Clock clock;
@Inject
MessageFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory) {
MessageFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory,
Clock clock) {
authorSignature = crypto.getSignature();
groupSignature = crypto.getSignature();
random = crypto.getSecureRandom();
messageDigest = crypto.getMessageDigest();
this.writerFactory = writerFactory;
this.clock = clock;
}
public Message createMessage(MessageId parent, String subject, byte[] body)
@@ -115,7 +119,7 @@ class MessageFactoryImpl implements MessageFactory {
if(author == null) w.writeNull();
else writeAuthor(w, author);
w.writeString(subject);
long timestamp = System.currentTimeMillis();
long timestamp = clock.currentTimeMillis();
w.writeInt64(timestamp);
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);

View File

@@ -6,6 +6,7 @@ import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.reliability.ReadHandler;
class Receiver implements ReadHandler {
@@ -13,6 +14,7 @@ class Receiver implements ReadHandler {
private static final int READ_TIMEOUT = 5 * 60 * 1000; // Milliseconds
private static final int MAX_WINDOW_SIZE = 8 * Data.MAX_PAYLOAD_LENGTH;
private final Clock clock;
private final Sender sender;
private final SortedSet<Data> dataFrames; // Locking: this
@@ -22,13 +24,14 @@ class Receiver implements ReadHandler {
private volatile boolean valid = true;
Receiver(Sender sender) {
Receiver(Clock clock, Sender sender) {
this.sender = sender;
this.clock = clock;
dataFrames = new TreeSet<Data>(new SequenceNumberComparator());
}
synchronized Data read() throws IOException, InterruptedException {
long now = System.currentTimeMillis(), end = now + READ_TIMEOUT;
long now = clock.currentTimeMillis(), end = now + READ_TIMEOUT;
while(now < end && valid) {
if(dataFrames.isEmpty()) {
// Wait for a data frame
@@ -47,7 +50,7 @@ class Receiver implements ReadHandler {
wait(end - now);
}
}
now = System.currentTimeMillis();
now = clock.currentTimeMillis();
}
if(valid) throw new IOException("Read timed out");
throw new IOException("Connection closed");

View File

@@ -2,6 +2,8 @@ package net.sf.briar.reliability;
import java.util.concurrent.Executor;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.clock.SystemClock;
import net.sf.briar.api.reliability.ReliabilityLayer;
import net.sf.briar.api.reliability.ReliabilityLayerFactory;
import net.sf.briar.api.reliability.WriteHandler;
@@ -9,12 +11,14 @@ import net.sf.briar.api.reliability.WriteHandler;
class ReliabilityLayerFactoryImpl implements ReliabilityLayerFactory {
private final Executor executor;
private final Clock clock;
ReliabilityLayerFactoryImpl(Executor executor) {
this.executor = executor;
clock = new SystemClock();
}
public ReliabilityLayer createReliabilityLayer(WriteHandler writeHandler) {
return new ReliabilityLayerImpl(executor, writeHandler);
return new ReliabilityLayerImpl(executor, clock, writeHandler);
}
}

View File

@@ -11,6 +11,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.reliability.ReliabilityLayer;
import net.sf.briar.api.reliability.WriteHandler;
@@ -22,6 +23,7 @@ class ReliabilityLayerImpl implements ReliabilityLayer, WriteHandler {
Logger.getLogger(ReliabilityLayerImpl.class.getName());
private final Executor executor;
private final Clock clock;
private final WriteHandler writeHandler;
private final BlockingQueue<byte[]> writes;
@@ -31,23 +33,25 @@ class ReliabilityLayerImpl implements ReliabilityLayer, WriteHandler {
private volatile SenderOutputStream outputStream = null;
private volatile boolean running = false;
ReliabilityLayerImpl(Executor executor, WriteHandler writeHandler) {
ReliabilityLayerImpl(Executor executor, Clock clock,
WriteHandler writeHandler) {
this.executor = executor;
this.clock = clock;
this.writeHandler = writeHandler;
writes = new LinkedBlockingQueue<byte[]>();
}
public void start() {
SlipEncoder encoder = new SlipEncoder(this);
final Sender sender = new Sender(encoder);
receiver = new Receiver(sender);
final Sender sender = new Sender(clock, encoder);
receiver = new Receiver(clock, sender);
decoder = new SlipDecoder(receiver);
inputStream = new ReceiverInputStream(receiver);
outputStream = new SenderOutputStream(sender);
running = true;
executor.execute(new Runnable() {
public void run() {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
long next = now + TICK_INTERVAL;
try {
while(running) {
@@ -55,7 +59,7 @@ class ReliabilityLayerImpl implements ReliabilityLayer, WriteHandler {
while(now < next && b == null) {
b = writes.poll(next - now, MILLISECONDS);
if(!running) return;
now = System.currentTimeMillis();
now = clock.currentTimeMillis();
}
if(b == null) {
sender.tick();

View File

@@ -6,6 +6,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.reliability.WriteHandler;
class Sender {
@@ -18,6 +19,7 @@ class Sender {
private static final int INITIAL_RTT_VAR = 3 * 1000;
private static final int MAX_WINDOW_SIZE = 64 * Data.MAX_PAYLOAD_LENGTH;
private final Clock clock;
private final WriteHandler writeHandler;
private final LinkedList<Outstanding> outstanding; // Locking: this
@@ -29,7 +31,8 @@ class Sender {
private long lastWindowUpdateOrProbe = Long.MAX_VALUE;
private boolean dataWaiting = false;
Sender(WriteHandler writeHandler) {
Sender(Clock clock, WriteHandler writeHandler) {
this.clock = clock;
this.writeHandler = writeHandler;
outstanding = new LinkedList<Outstanding>();
}
@@ -53,7 +56,7 @@ class Sender {
return;
}
long sequenceNumber = a.getSequenceNumber();
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
Outstanding fastRetransmit = null;
synchronized(this) {
// Remove the acked data frame if it's outstanding
@@ -99,7 +102,7 @@ class Sender {
}
void tick() throws IOException {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
List<Outstanding> retransmit = null;
boolean sendProbe = false;
synchronized(this) {
@@ -150,15 +153,15 @@ class Sender {
int payloadLength = d.getPayloadLength();
synchronized(this) {
// Wait for space in the window
long now = System.currentTimeMillis(), end = now + WRITE_TIMEOUT;
long now = clock.currentTimeMillis(), end = now + WRITE_TIMEOUT;
while(now < end && outstandingBytes + payloadLength >= windowSize) {
dataWaiting = true;
wait(end - now);
now = System.currentTimeMillis();
now = clock.currentTimeMillis();
}
if(outstandingBytes + payloadLength >= windowSize)
throw new IOException("Write timed out");
outstanding.add(new Outstanding(d));
outstanding.add(new Outstanding(d, now));
outstandingBytes += payloadLength;
dataWaiting = false;
}
@@ -176,9 +179,9 @@ class Sender {
private volatile long lastTransmitted;
private volatile boolean retransmitted;
private Outstanding(Data data) {
private Outstanding(Data data, long lastTransmitted) {
this.data = data;
lastTransmitted = System.currentTimeMillis();
this.lastTransmitted = lastTransmitted;
retransmitted = false;
}
}

View File

@@ -12,6 +12,7 @@ import java.util.TimerTask;
import java.util.logging.Logger;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.clock.Timer;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.KeyManager;
@@ -39,6 +40,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
private final CryptoComponent crypto;
private final DatabaseComponent db;
private final ConnectionRecogniser recogniser;
private final Clock clock;
private final Timer timer;
// Locking: this
private final Map<ContactTransportKey, TemporarySecret> outgoing;
@@ -49,10 +51,11 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
@Inject
KeyManagerImpl(CryptoComponent crypto, DatabaseComponent db,
ConnectionRecogniser recogniser, Timer timer) {
ConnectionRecogniser recogniser, Clock clock, Timer timer) {
this.crypto = crypto;
this.db = db;
this.recogniser = recogniser;
this.clock = clock;
this.timer = timer;
outgoing = new HashMap<ContactTransportKey, TemporarySecret>();
incomingOld = new HashMap<ContactTransportKey, TemporarySecret>();
@@ -68,7 +71,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
return false;
}
// Work out what phase of its lifecycle each secret is in
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
Collection<TemporarySecret> dead = assignSecretsToMaps(now, secrets);
// Replace any dead secrets
Collection<TemporarySecret> created = replaceDeadSecrets(now, dead);
@@ -233,7 +236,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
public synchronized void contactTransportAdded(ContactTransport ct,
byte[] initialSecret) {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
long rotationPeriod = getRotationPeriod(ct);
long elapsed = now - ct.getEpoch();
long currentPeriod = elapsed / rotationPeriod;
@@ -288,7 +291,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
incomingOld.clear();
incomingNew.clear();
// Work out what phase of its lifecycle each secret is in
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
Collection<TemporarySecret> dead = assignSecretsToMaps(now, secrets);
// Remove any dead secrets from the recogniser
for(TemporarySecret s : dead) {

View File

@@ -9,8 +9,8 @@ import java.util.concurrent.Executors;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.clock.SystemClock;
import net.sf.briar.plugins.DuplexClientTest;
import net.sf.briar.plugins.tcp.LanTcpPlugin;
// This is not a JUnit test - it has to be run manually while the server test
// is running on another machine
@@ -27,7 +27,7 @@ public class LanTcpClientTest extends DuplexClientTest {
// Create the plugin
callback = new ClientCallback(new TransportConfig(),
new TransportProperties(), remote);
plugin = new LanTcpPlugin(executor, callback, 0L);
plugin = new LanTcpPlugin(executor, new SystemClock(), callback, 0L);
}
public static void main(String[] args) throws Exception {

View File

@@ -17,10 +17,11 @@ import net.sf.briar.BriarTestCase;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.clock.SystemClock;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
import net.sf.briar.plugins.tcp.LanTcpPlugin;
import org.junit.Test;
@@ -33,8 +34,9 @@ public class LanTcpPluginTest extends BriarTestCase {
Callback callback = new Callback();
callback.local.put("address", "127.0.0.1");
callback.local.put("port", "0");
Executor e = Executors.newCachedThreadPool();
DuplexPlugin plugin = new LanTcpPlugin(e, callback, 0L);
Executor executor = Executors.newCachedThreadPool();
Clock clock = new SystemClock();
DuplexPlugin plugin = new LanTcpPlugin(executor, clock, callback, 0L);
plugin.start();
// The plugin should have bound a socket and stored the port number
assertTrue(callback.propertiesLatch.await(5, SECONDS));
@@ -58,8 +60,9 @@ public class LanTcpPluginTest extends BriarTestCase {
@Test
public void testOutgoingConnection() throws Exception {
Callback callback = new Callback();
Executor e = Executors.newCachedThreadPool();
DuplexPlugin plugin = new LanTcpPlugin(e, callback, 0L);
Executor executor = Executors.newCachedThreadPool();
Clock clock = new SystemClock();
DuplexPlugin plugin = new LanTcpPlugin(executor, clock, callback, 0L);
plugin.start();
// Listen on a local port
final ServerSocket ss = new ServerSocket();

View File

@@ -7,8 +7,8 @@ import java.util.concurrent.Executors;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.clock.SystemClock;
import net.sf.briar.plugins.DuplexServerTest;
import net.sf.briar.plugins.tcp.LanTcpPlugin;
// This is not a JUnit test - it has to be run manually while the client test
// is running on another machine
@@ -18,7 +18,7 @@ public class LanTcpServerTest extends DuplexServerTest {
callback = new ServerCallback(new TransportConfig(),
new TransportProperties(),
Collections.singletonMap(contactId, new TransportProperties()));
plugin = new LanTcpPlugin(executor, callback, 0L);
plugin = new LanTcpPlugin(executor, new SystemClock(), callback, 0L);
}
public static void main(String[] args) throws Exception {

View File

@@ -38,6 +38,7 @@ import net.sf.briar.api.protocol.Transport;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.protocol.TransportUpdate;
import net.sf.briar.api.protocol.UniqueId;
import net.sf.briar.clock.ClockModule;
import net.sf.briar.crypto.CryptoModule;
import net.sf.briar.serial.SerialModule;
@@ -57,7 +58,7 @@ public class ConstantsTest extends BriarTestCase {
public ConstantsTest() throws Exception {
super();
Injector i = Guice.createInjector(new CryptoModule(),
Injector i = Guice.createInjector(new ClockModule(), new CryptoModule(),
new ProtocolModule(), new SerialModule());
crypto = i.getInstance(CryptoComponent.class);
groupFactory = i.getInstance(GroupFactory.class);

View File

@@ -29,6 +29,7 @@ import net.sf.briar.api.protocol.SubscriptionUpdate;
import net.sf.briar.api.protocol.Transport;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.protocol.TransportUpdate;
import net.sf.briar.clock.ClockModule;
import net.sf.briar.crypto.CryptoModule;
import net.sf.briar.serial.SerialModule;
@@ -54,7 +55,7 @@ public class ProtocolIntegrationTest extends BriarTestCase {
public ProtocolIntegrationTest() throws Exception {
super();
Injector i = Guice.createInjector(new CryptoModule(),
Injector i = Guice.createInjector(new ClockModule(), new CryptoModule(),
new ProtocolModule(), new SerialModule());
readerFactory = i.getInstance(ProtocolReaderFactory.class);
writerFactory = i.getInstance(ProtocolWriterFactory.class);

View File

@@ -10,6 +10,7 @@ import net.sf.briar.api.protocol.ProtocolWriter;
import net.sf.briar.api.protocol.Request;
import net.sf.briar.api.serial.SerialComponent;
import net.sf.briar.api.serial.WriterFactory;
import net.sf.briar.clock.ClockModule;
import net.sf.briar.crypto.CryptoModule;
import net.sf.briar.serial.SerialModule;
import net.sf.briar.util.StringUtils;
@@ -29,7 +30,7 @@ public class ProtocolWriterImplTest extends BriarTestCase {
public ProtocolWriterImplTest() {
super();
Injector i = Guice.createInjector(new CryptoModule(),
Injector i = Guice.createInjector(new ClockModule(), new CryptoModule(),
new ProtocolModule(), new SerialModule());
packetFactory = i.getInstance(PacketFactory.class);
serial = i.getInstance(SerialComponent.class);

View File

@@ -15,6 +15,7 @@ import net.sf.briar.api.serial.Reader;
import net.sf.briar.api.serial.ReaderFactory;
import net.sf.briar.api.serial.Writer;
import net.sf.briar.api.serial.WriterFactory;
import net.sf.briar.clock.ClockModule;
import net.sf.briar.crypto.CryptoModule;
import net.sf.briar.serial.SerialModule;
@@ -36,7 +37,7 @@ public class RequestReaderTest extends BriarTestCase {
public RequestReaderTest() throws Exception {
super();
Injector i = Guice.createInjector(new CryptoModule(),
Injector i = Guice.createInjector(new ClockModule(), new CryptoModule(),
new ProtocolModule(), new SerialModule());
readerFactory = i.getInstance(ReaderFactory.class);
writerFactory = i.getInstance(WriterFactory.class);