Skip to content
Snippets Groups Projects
Commit 7b8181e3 authored by akwizgran's avatar akwizgran
Browse files

Massive refactoring to merge handling of simplex and duplex connections.

parent b24f1537
No related branches found
No related tags found
No related merge requests found
Showing
with 244 additions and 145 deletions
......@@ -3,8 +3,11 @@ package org.briarproject.plugins.droidtooth;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.atomic.AtomicBoolean;
import org.briarproject.api.plugins.Plugin;
import org.briarproject.api.plugins.TransportConnectionReader;
import org.briarproject.api.plugins.TransportConnectionWriter;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import android.bluetooth.BluetoothSocket;
......@@ -13,30 +16,69 @@ class DroidtoothTransportConnection implements DuplexTransportConnection {
private final Plugin plugin;
private final BluetoothSocket socket;
private final Reader reader;
private final Writer writer;
private final AtomicBoolean halfClosed, closed;
DroidtoothTransportConnection(Plugin plugin, BluetoothSocket socket) {
this.plugin = plugin;
this.socket = socket;
reader = new Reader();
writer = new Writer();
halfClosed = new AtomicBoolean(false);
closed = new AtomicBoolean(false);
}
public int getMaxFrameLength() {
return plugin.getMaxFrameLength();
public TransportConnectionReader getReader() {
return reader;
}
public long getMaxLatency() {
return plugin.getMaxLatency();
public TransportConnectionWriter getWriter() {
return writer;
}
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}
private class Reader implements TransportConnectionReader {
public int getMaxFrameLength() {
return plugin.getMaxFrameLength();
}
public long getMaxLatency() {
return plugin.getMaxLatency();
}
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}
public void dispose(boolean exception, boolean recognised)
throws IOException {
if(halfClosed.getAndSet(true) || exception)
if(!closed.getAndSet(true)) socket.close();
}
}
public void dispose(boolean exception, boolean recognised)
throws IOException {
socket.close();
private class Writer implements TransportConnectionWriter {
public int getMaxFrameLength() {
return plugin.getMaxFrameLength();
}
public long getMaxLatency() {
return plugin.getMaxLatency();
}
public long getCapacity() {
return Long.MAX_VALUE;
}
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}
public void dispose(boolean exception) throws IOException {
if(halfClosed.getAndSet(true) || exception)
if(!closed.getAndSet(true)) socket.close();
}
}
}
......@@ -4,38 +4,80 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicBoolean;
import org.briarproject.api.plugins.Plugin;
import org.briarproject.api.plugins.TransportConnectionReader;
import org.briarproject.api.plugins.TransportConnectionWriter;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
class TorTransportConnection implements DuplexTransportConnection {
private final Plugin plugin;
private final Socket socket;
private final Reader reader;
private final Writer writer;
private final AtomicBoolean halfClosed, closed;
TorTransportConnection(Plugin plugin, Socket socket) {
this.plugin = plugin;
this.socket = socket;
reader = new Reader();
writer = new Writer();
halfClosed = new AtomicBoolean(false);
closed = new AtomicBoolean(false);
}
public int getMaxFrameLength() {
return plugin.getMaxFrameLength();
public TransportConnectionReader getReader() {
return reader;
}
public long getMaxLatency() {
return plugin.getMaxLatency();
public TransportConnectionWriter getWriter() {
return writer;
}
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}
private class Reader implements TransportConnectionReader {
public int getMaxFrameLength() {
return plugin.getMaxFrameLength();
}
public long getMaxLatency() {
return plugin.getMaxLatency();
}
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}
public void dispose(boolean exception, boolean recognised)
throws IOException {
if(halfClosed.getAndSet(true) || exception)
if(!closed.getAndSet(true)) socket.close();
}
}
public void dispose(boolean exception, boolean recognised)
throws IOException {
socket.close();
private class Writer implements TransportConnectionWriter {
public int getMaxFrameLength() {
return plugin.getMaxFrameLength();
}
public long getMaxLatency() {
return plugin.getMaxLatency();
}
public long getCapacity() {
return Long.MAX_VALUE;
}
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}
public void dispose(boolean exception) throws IOException {
if(halfClosed.getAndSet(true) || exception)
if(!closed.getAndSet(true)) socket.close();
}
}
}
......@@ -72,13 +72,10 @@ public interface CryptoComponent {
/**
* Derives a frame key from the given temporary secret and stream number.
* @param alice indicates whether the key is for a connection initiated by
* @param alice indicates whether the key is for a stream initiated by
* Alice or Bob.
* @param initiator indicates whether the key is for the initiator's or the
* responder's side of the connection.
*/
SecretKey deriveFrameKey(byte[] secret, long streamNumber, boolean alice,
boolean initiator);
SecretKey deriveFrameKey(byte[] secret, long streamNumber, boolean alice);
/** Returns a cipher for encrypting and authenticating frames. */
AuthenticatedCipher getFrameCipher();
......
package org.briarproject.api.messaging;
import java.io.IOException;
public interface MessagingSession {
/**
* Runs the session. This method returns when there are no more packets to
* send or when the {@link #interrupt()} method has been called.
*/
void run() throws IOException;
/**
* Interrupts the session, causing the {@link #run()} method to return at
* the next opportunity or throw an {@link java.io.IOException IOException}
* if it cannot return cleanly.
*/
void interrupt();
}
package org.briarproject.api.messaging;
import org.briarproject.api.plugins.TransportConnectionReader;
import org.briarproject.api.plugins.TransportConnectionWriter;
import org.briarproject.api.transport.StreamContext;
public interface MessagingSessionFactory {
MessagingSession createIncomingSession(StreamContext ctx,
TransportConnectionReader r);
MessagingSession createOutgoingSession(StreamContext ctx,
TransportConnectionWriter w, boolean duplex);
}
package org.briarproject.api.messaging.duplex;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.transport.StreamContext;
public interface DuplexConnectionFactory {
void createIncomingConnection(StreamContext ctx,
DuplexTransportConnection d);
void createOutgoingConnection(ContactId c, TransportId t,
DuplexTransportConnection d);
}
package org.briarproject.api.messaging.simplex;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.plugins.simplex.SimplexTransportReader;
import org.briarproject.api.plugins.simplex.SimplexTransportWriter;
import org.briarproject.api.transport.StreamContext;
public interface SimplexConnectionFactory {
void createIncomingConnection(StreamContext ctx,
SimplexTransportReader r);
void createOutgoingConnection(ContactId c, TransportId t,
SimplexTransportWriter w);
}
package org.briarproject.api.plugins;
import java.io.IOException;
import java.io.InputStream;
/**
* An interface for reading data from a transport connection. The reader is not
* responsible for decrypting or authenticating the data.
*/
public interface TransportConnectionReader {
/** Returns the maximum frame length of the transport in bytes. */
int getMaxFrameLength();
/** Returns the maximum latency of the transport in milliseconds. */
long getMaxLatency();
/** Returns an input stream for reading from the transport connection. */
InputStream getInputStream() throws IOException;
/**
* Marks this side of the transport connection closed. If the transport is
* simplex, the connection is closed. If the transport is duplex, the
* connection is closed if <tt>exception</tt> is true or the other side of
* the connection has been marked as closed.
* @param exception true if the connection is being closed because of an
* exception. This may affect how resources are disposed of.
* @param recognised true if the pseudo-random tag was recognised. This may
* affect how resources are disposed of.
*/
void dispose(boolean exception, boolean recognised) throws IOException;
}
package org.briarproject.api.plugins.simplex;
package org.briarproject.api.plugins;
import java.io.IOException;
import java.io.OutputStream;
/**
* An interface for writing data to a simplex transport. The writer is not
* responsible for authenticating or encrypting the data before writing it.
* An interface for writing data to a transport connection. The writer is not
* responsible for authenticating or encrypting the data.
*/
public interface SimplexTransportWriter {
/** Returns the capacity of the transport in bytes. */
long getCapacity();
public interface TransportConnectionWriter {
/** Returns the maximum frame length of the transport in bytes. */
int getMaxFrameLength();
......@@ -18,13 +15,19 @@ public interface SimplexTransportWriter {
/** Returns the maximum latency of the transport in milliseconds. */
long getMaxLatency();
/** Returns an output stream for writing to the transport. */
/** Returns the capacity of the transport connection in bytes. */
long getCapacity();
/** Returns an output stream for writing to the transport connection. */
OutputStream getOutputStream() throws IOException;
/**
* Closes the writer and disposes of any associated resources. The
* argument indicates whether the writer is being closed because of an
* exception, which may affect how resources are disposed of.
* Marks this side of the transport connection closed. If the transport is
* simplex, the connection is closed. If the transport is duplex, the
* connection is closed if <tt>exception</tt> is true or the other side of
* the connection has been marked as closed.
* @param exception true if the connection is being closed because of an
* exception. This may affect how resources are disposed of.
*/
void dispose(boolean exception) throws IOException;
}
package org.briarproject.api.plugins.duplex;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.briarproject.api.plugins.TransportConnectionReader;
import org.briarproject.api.plugins.TransportConnectionWriter;
/**
* An interface for reading and writing data over a duplex transport. The
......@@ -11,23 +10,11 @@ import java.io.OutputStream;
*/
public interface DuplexTransportConnection {
/** Returns the maximum frame length of the transport in bytes. */
int getMaxFrameLength();
/** Returns a {@link org.briarproject.api.plugins.TransportConnectionReader
* TransportConnectionReader} for reading from the connection. */
TransportConnectionReader getReader();
/** Returns the maximum latency of the transport in milliseconds. */
long getMaxLatency();
/** Returns an input stream for reading from the connection. */
InputStream getInputStream() throws IOException;
/** Returns an output stream for writing to the connection. */
OutputStream getOutputStream() throws IOException;
/**
* Closes the connection and disposes of any associated resources. The
* first argument indicates whether the connection is being closed because
* of an exception and the second argument indicates whether the connection
* was recognised, which may affect how resources are disposed of.
*/
void dispose(boolean exception, boolean recognised) throws IOException;
/** Returns a {@link org.briarproject.api.plugins.TransportConnectionWriter
* TransportConnectionWriter} for writing to the connection. */
TransportConnectionWriter getWriter();
}
......@@ -2,6 +2,8 @@ package org.briarproject.api.plugins.simplex;
import org.briarproject.api.ContactId;
import org.briarproject.api.plugins.Plugin;
import org.briarproject.api.plugins.TransportConnectionReader;
import org.briarproject.api.plugins.TransportConnectionWriter;
/** An interface for transport plugins that support simplex communication. */
public interface SimplexPlugin extends Plugin {
......@@ -11,12 +13,12 @@ public interface SimplexPlugin extends Plugin {
* current transport and configuration properties. Returns null if a reader
* could not be created.
*/
SimplexTransportReader createReader(ContactId c);
TransportConnectionReader createReader(ContactId c);
/**
* Attempts to create and return a writer for the given contact using the
* current transport and configuration properties. Returns null if a writer
* could not be created.
*/
SimplexTransportWriter createWriter(ContactId c);
TransportConnectionWriter createWriter(ContactId c);
}
......@@ -2,6 +2,8 @@ package org.briarproject.api.plugins.simplex;
import org.briarproject.api.ContactId;
import org.briarproject.api.plugins.PluginCallback;
import org.briarproject.api.plugins.TransportConnectionReader;
import org.briarproject.api.plugins.TransportConnectionWriter;
/**
* An interface for handling readers and writers created by a simplex transport
......@@ -9,7 +11,7 @@ import org.briarproject.api.plugins.PluginCallback;
*/
public interface SimplexPluginCallback extends PluginCallback {
void readerCreated(SimplexTransportReader r);
void readerCreated(TransportConnectionReader r);
void writerCreated(ContactId c, SimplexTransportWriter w);
void writerCreated(ContactId c, TransportConnectionWriter w);
}
package org.briarproject.api.plugins.simplex;
import java.io.IOException;
import java.io.InputStream;
/**
* An interface for reading data from a simplex transport. The reader is not
* responsible for decrypting or authenticating the data before returning it.
*/
public interface SimplexTransportReader {
/** Returns the maximum frame length of the transport in bytes. */
int getMaxFrameLength();
/** Returns an input stream for reading from the transport. */
InputStream getInputStream() throws IOException;
/**
* Closes the reader and disposes of any associated resources. The first
* argument indicates whether the reader is being closed because of an
* exception and the second argument indicates whether the connection was
* recognised, which may affect how resources are disposed of.
*/
void dispose(boolean exception, boolean recognised) throws IOException;
}
......@@ -2,18 +2,18 @@ package org.briarproject.api.transport;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.plugins.TransportConnectionReader;
import org.briarproject.api.plugins.TransportConnectionWriter;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.plugins.simplex.SimplexTransportReader;
import org.briarproject.api.plugins.simplex.SimplexTransportWriter;
public interface ConnectionDispatcher {
void dispatchIncomingConnection(TransportId t, SimplexTransportReader r);
void dispatchIncomingConnection(TransportId t, TransportConnectionReader r);
void dispatchIncomingConnection(TransportId t, DuplexTransportConnection d);
void dispatchOutgoingConnection(ContactId c, TransportId t,
SimplexTransportWriter w);
TransportConnectionWriter w);
void dispatchOutgoingConnection(ContactId c, TransportId t,
DuplexTransportConnection d);
......
......@@ -6,7 +6,7 @@ public interface StreamReaderFactory {
/** Creates a {@link StreamReader} for a transport connection. */
StreamReader createStreamReader(InputStream in, int maxFrameLength,
StreamContext ctx, boolean incoming, boolean initiator);
StreamContext ctx);
/** Creates a {@link StreamReader} for an invitation connection. */
StreamReader createInvitationStreamReader(InputStream in,
......
......@@ -10,10 +10,4 @@ public interface StreamWriter {
* be written.
*/
OutputStream getOutputStream();
/**
* Returns the maximum number of bytes that can be written to the output
* stream.
*/
long getRemainingCapacity();
}
......@@ -6,8 +6,7 @@ public interface StreamWriterFactory {
/** Creates a {@link StreamWriter} for a transport connection. */
StreamWriter createStreamWriter(OutputStream out, int maxFrameLength,
long capacity, StreamContext ctx, boolean incoming,
boolean initiator);
StreamContext ctx);
/** Creates a {@link StreamWriter} for an invitation connection. */
StreamWriter createInvitationStreamWriter(OutputStream out,
......
......@@ -4,12 +4,13 @@ import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.db.DbException;
/** Maintains the table of expected tags for recognising incoming streams. */
/** Keeps track of expected tags and uses them to recognise incoming streams. */
public interface TagRecogniser {
/**
* Returns a {@link StreamContext} for reading from the stream with the
* given tag if the tag was expected, or null if the tag was unexpected.
* Looks up the given tag and returns a {@link StreamContext} for reading
* from the stream if the tag was expected, or null if the tag was
* unexpected.
*/
StreamContext recogniseTag(TransportId t, byte[] tag) throws DbException;
......
......@@ -76,14 +76,10 @@ class CryptoComponentImpl implements CryptoComponent {
// Labels for key derivation
private static final byte[] A_TAG = { 'A', '_', 'T', 'A', 'G', '\0' };
private static final byte[] B_TAG = { 'B', '_', 'T', 'A', 'G', '\0' };
private static final byte[] A_FRAME_A =
{ 'A', '_', 'F', 'R', 'A', 'M', 'E', '_', 'A', '\0' };
private static final byte[] A_FRAME_B =
{ 'A', '_', 'F', 'R', 'A', 'M', 'E', '_', 'B', '\0' };
private static final byte[] B_FRAME_A =
{ 'B', '_', 'F', 'R', 'A', 'M', 'E', '_', 'A', '\0' };
private static final byte[] B_FRAME_B =
{ 'B', '_', 'F', 'R', 'A', 'M', 'E', '_', 'B', '\0' };
private static final byte[] A_FRAME =
{ 'A', '_', 'F', 'R', 'A', 'M', 'E', '\0' };
private static final byte[] B_FRAME =
{ 'B', '_', 'F', 'R', 'A', 'M', 'E', '\0' };
// Blank secret for argument validation
private static final byte[] BLANK_SECRET = new byte[CIPHER_KEY_BYTES];
......@@ -288,20 +284,15 @@ class CryptoComponentImpl implements CryptoComponent {
}
public SecretKey deriveFrameKey(byte[] secret, long streamNumber,
boolean alice, boolean initiator) {
boolean alice) {
if(secret.length != CIPHER_KEY_BYTES)
throw new IllegalArgumentException();
if(Arrays.equals(secret, BLANK_SECRET))
throw new IllegalArgumentException();
if(streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
throw new IllegalArgumentException();
if(alice) {
if(initiator) return deriveKey(secret, A_FRAME_A, streamNumber);
else return deriveKey(secret, A_FRAME_B, streamNumber);
} else {
if(initiator) return deriveKey(secret, B_FRAME_A, streamNumber);
else return deriveKey(secret, B_FRAME_B, streamNumber);
}
if(alice) return deriveKey(secret, A_FRAME, streamNumber);
else return deriveKey(secret, B_FRAME, streamNumber);
}
private SecretKey deriveKey(byte[] secret, byte[] label, long context) {
......
......@@ -75,8 +75,8 @@ class AliceConnector extends Connector {
Writer w;
byte[] secret;
try {
in = conn.getInputStream();
out = conn.getOutputStream();
in = conn.getReader().getInputStream();
out = conn.getWriter().getOutputStream();
r = readerFactory.createReader(in);
w = writerFactory.createWriter(out);
// Alice goes first
......@@ -130,7 +130,7 @@ class AliceConnector extends Connector {
// Confirmation succeeded - upgrade to a secure connection
if(LOG.isLoggable(INFO))
LOG.info(pluginName + " confirmation succeeded");
int maxFrameLength = conn.getMaxFrameLength();
int maxFrameLength = conn.getReader().getMaxFrameLength();
StreamReader streamReader =
streamReaderFactory.createInvitationStreamReader(in,
maxFrameLength, secret, false);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment