From 1886609befb14d8f34320afab04277b031655c72 Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Thu, 8 Dec 2011 14:35:52 +0000 Subject: [PATCH] Removed frame padding code (soon to be obsolete). --- .../sf/briar/transport/FrameScheduler.java | 44 ----- .../transport/PaddedConnectionWriter.java | 122 ------------- test/build.xml | 1 - .../transport/PaddedConnectionWriterTest.java | 163 ------------------ 4 files changed, 330 deletions(-) delete mode 100644 components/net/sf/briar/transport/FrameScheduler.java delete mode 100644 components/net/sf/briar/transport/PaddedConnectionWriter.java delete mode 100644 test/net/sf/briar/transport/PaddedConnectionWriterTest.java diff --git a/components/net/sf/briar/transport/FrameScheduler.java b/components/net/sf/briar/transport/FrameScheduler.java deleted file mode 100644 index 1a3f02d065..0000000000 --- a/components/net/sf/briar/transport/FrameScheduler.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.sf.briar.transport; - -import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; - -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * A thread that calls the writeFullFrame() method of a PaddedConnectionWriter - * at regular intervals. The interval between calls is determined by a target - * output rate. If the underlying output stream cannot accept data at the - * target rate, calls will be made as frequently as the output stream allows. - */ -class FrameScheduler extends Thread { - - private static final Logger LOG = - Logger.getLogger(FrameScheduler.class.getName()); - - private final PaddedConnectionWriter writer; - private final int millisPerFrame; - - FrameScheduler(PaddedConnectionWriter writer, int bytesPerSecond) { - this.writer = writer; - millisPerFrame = bytesPerSecond * 1000 / MAX_FRAME_LENGTH; - } - - @Override - public void run() { - long lastCall = System.currentTimeMillis(); - try { - while(true) { - long now = System.currentTimeMillis(); - long nextCall = lastCall + millisPerFrame; - if(nextCall > now) Thread.sleep(nextCall - now); - lastCall = System.currentTimeMillis(); - if(!writer.writeFullFrame()) return; - } - } catch(InterruptedException e) { - if(LOG.isLoggable(Level.INFO)) - LOG.info("Interrupted while waiting to write frame"); - Thread.currentThread().interrupt(); - } - } -} \ No newline at end of file diff --git a/components/net/sf/briar/transport/PaddedConnectionWriter.java b/components/net/sf/briar/transport/PaddedConnectionWriter.java deleted file mode 100644 index 4bdbb5572e..0000000000 --- a/components/net/sf/briar/transport/PaddedConnectionWriter.java +++ /dev/null @@ -1,122 +0,0 @@ -package net.sf.briar.transport; - -import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; - -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.crypto.Mac; - -import net.sf.briar.api.crypto.ErasableKey; -import net.sf.briar.util.ByteUtils; - -/** - * A ConnectionWriter that uses padding to hinder traffic analysis. A full-size - * frame is written each time the writeFullFrame() method is called, with - * padding inserted if necessary. Calls to the writer's write() methods will - * block until there is space to buffer the data. - */ -class PaddedConnectionWriter extends ConnectionWriterImpl { - - private static final Logger LOG = - Logger.getLogger(PaddedConnectionWriter.class.getName()); - - private final byte[] padding; - - private boolean closed = false; - private IOException exception = null; - - PaddedConnectionWriter(ConnectionEncrypter encrypter, Mac mac, - ErasableKey macKey) { - super(encrypter, mac, macKey); - padding = new byte[maxPayloadLength]; - } - - @Override - public synchronized void close() throws IOException { - if(exception != null) throw exception; - if(buf.size() > 0) writeFrame(false); - out.flush(); - out.close(); - closed = true; - } - - @Override - public void flush() throws IOException { - // Na na na, I can't hear you - } - - @Override - public synchronized void write(int b) throws IOException { - if(exception != null) throw exception; - if(buf.size() == maxPayloadLength) waitForSpace(); - buf.write(b); - } - - @Override - public void write(byte[] b) throws IOException { - write(b, 0, b.length); - } - - @Override - public synchronized void write(byte[] b, int off, int len) - throws IOException { - if(exception != null) throw exception; - int available = maxPayloadLength - buf.size(); - while(available < len) { - buf.write(b, off, available); - off += available; - len -= available; - waitForSpace(); - available = maxPayloadLength; - } - buf.write(b, off, len); - } - - /** - * Attempts to write a full-size frame, inserting padding if necessary, and - * returns true if the frame was written. If this method returns false it - * should not be called again. - */ - synchronized boolean writeFullFrame() { - if(closed) return false; - try { - writeFrame(true); - notify(); - return true; - } catch(IOException e) { - exception = e; - return false; - } - } - - private synchronized void writeFrame(boolean pad) throws IOException { - if(frame > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); - byte[] payload = buf.toByteArray(); - if(payload.length > maxPayloadLength) throw new IllegalStateException(); - int paddingLength = pad ? maxPayloadLength - payload.length : 0; - ByteUtils.writeUint16(payload.length, header, 0); - ByteUtils.writeUint16(paddingLength, header, 2); - out.write(header); - mac.update(header); - out.write(payload); - mac.update(payload); - out.write(padding, 0, paddingLength); - mac.update(padding, 0, paddingLength); - encrypter.writeFinal(mac.doFinal()); - frame++; - buf.reset(); - } - - private synchronized void waitForSpace() throws IOException { - try { - wait(); - } catch(InterruptedException e) { - if(LOG.isLoggable(Level.INFO)) - LOG.info("Interrupted while waiting for space"); - Thread.currentThread().interrupt(); - } - if(exception != null) throw exception; - } -} diff --git a/test/build.xml b/test/build.xml index a37b43c243..ddb7c805fb 100644 --- a/test/build.xml +++ b/test/build.xml @@ -55,7 +55,6 @@ <test name='net.sf.briar.transport.ConnectionWriterImplTest'/> <test name='net.sf.briar.transport.ConnectionWriterTest'/> <test name='net.sf.briar.transport.FrameReadWriteTest'/> - <test name='net.sf.briar.transport.PaddedConnectionWriterTest'/> <test name='net.sf.briar.transport.batch.BatchConnectionReadWriteTest'/> <test name='net.sf.briar.util.ByteUtilsTest'/> <test name='net.sf.briar.util.FileUtilsTest'/> diff --git a/test/net/sf/briar/transport/PaddedConnectionWriterTest.java b/test/net/sf/briar/transport/PaddedConnectionWriterTest.java deleted file mode 100644 index cb35529079..0000000000 --- a/test/net/sf/briar/transport/PaddedConnectionWriterTest.java +++ /dev/null @@ -1,163 +0,0 @@ -package net.sf.briar.transport; - -import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import net.sf.briar.api.transport.ConnectionWriter; -import net.sf.briar.util.ByteUtils; - -import org.junit.Test; - -public class PaddedConnectionWriterTest extends TransportTest { - - public PaddedConnectionWriterTest() throws Exception { - super(); - } - - @Test - public void testWriteByteDoesNotBlockUntilBufferIsFull() throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE); - ConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey); - final OutputStream out1 = w.getOutputStream(); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicBoolean finished = new AtomicBoolean(false); - final AtomicBoolean failed = new AtomicBoolean(false); - new Thread() { - @Override - public void run() { - try { - for(int i = 0; i < maxPayloadLength; i++) out1.write(0); - finished.set(true); - } catch(IOException e) { - failed.set(true); - } - latch.countDown(); - } - }.start(); - // The wait should not time out - assertTrue(latch.await(1, TimeUnit.SECONDS)); - assertTrue(finished.get()); - assertFalse(failed.get()); - // Nothing should have been written - assertEquals(0, out.size()); - } - - @Test - public void testWriteByteBlocksWhenBufferIsFull() throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE); - PaddedConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey); - final OutputStream out1 = w.getOutputStream(); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicBoolean finished = new AtomicBoolean(false); - final AtomicBoolean failed = new AtomicBoolean(false); - new Thread() { - @Override - public void run() { - try { - for(int i = 0; i < maxPayloadLength + 1; i++) out1.write(0); - finished.set(true); - } catch(IOException e) { - failed.set(true); - } - latch.countDown(); - } - }.start(); - // The wait should time out - assertFalse(latch.await(1, TimeUnit.SECONDS)); - assertFalse(finished.get()); - assertFalse(failed.get()); - // Calling writeFullFrame() should allow the writer to proceed - w.writeFullFrame(); - assertTrue(latch.await(1, TimeUnit.SECONDS)); - assertTrue(finished.get()); - assertFalse(failed.get()); - // A full frame should have been written - assertEquals(MAX_FRAME_LENGTH, out.size()); - } - - @Test - public void testWriteArrayDoesNotBlockUntilBufferIsFull() throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE); - ConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey); - final OutputStream out1 = w.getOutputStream(); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicBoolean finished = new AtomicBoolean(false); - final AtomicBoolean failed = new AtomicBoolean(false); - new Thread() { - @Override - public void run() { - try { - out1.write(new byte[maxPayloadLength]); - finished.set(true); - } catch(IOException e) { - failed.set(true); - } - latch.countDown(); - } - }.start(); - // The wait should not time out - assertTrue(latch.await(1, TimeUnit.SECONDS)); - assertTrue(finished.get()); - assertFalse(failed.get()); - // Nothing should have been written - assertEquals(0, out.size()); - } - - @Test - public void testWriteArrayBlocksWhenBufferIsFull() throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE); - PaddedConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey); - final OutputStream out1 = w.getOutputStream(); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicBoolean finished = new AtomicBoolean(false); - final AtomicBoolean failed = new AtomicBoolean(false); - new Thread() { - @Override - public void run() { - try { - out1.write(new byte[maxPayloadLength + 1]); - finished.set(true); - } catch(IOException e) { - failed.set(true); - } - latch.countDown(); - } - }.start(); - // The wait should time out - assertFalse(latch.await(1, TimeUnit.SECONDS)); - assertFalse(finished.get()); - assertFalse(failed.get()); - // Calling writeFullFrame() should allow the writer to proceed - w.writeFullFrame(); - assertTrue(latch.await(1, TimeUnit.SECONDS)); - assertTrue(finished.get()); - assertFalse(failed.get()); - // A full frame should have been written - assertEquals(MAX_FRAME_LENGTH, out.size()); - } - - @Test - public void testWriteFullFrameInsertsPadding() throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ConnectionEncrypter e = new NullConnectionEncrypter(out, Long.MAX_VALUE); - PaddedConnectionWriter w = new PaddedConnectionWriter(e, mac, macKey); - w.getOutputStream().write(0); - w.writeFullFrame(); - // A full frame should have been written - assertEquals(MAX_FRAME_LENGTH, out.size()); - // The frame should have a payload length of 1 and padding for the rest - byte[] frame = out.toByteArray(); - assertEquals(1, ByteUtils.readUint16(frame, 0)); // Payload length - assertEquals(maxPayloadLength - 1, ByteUtils.readUint16(frame, 2)); - } -} -- GitLab