mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 11:19:04 +01:00
Decoupled ProtocolReader (which belongs in the protocol component)
from PacketReader (which belongs in the transport component).
This commit is contained in:
@@ -12,6 +12,7 @@ import net.sf.briar.api.protocol.Message;
|
||||
import net.sf.briar.api.protocol.MessageEncoder;
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
import net.sf.briar.api.protocol.ProtocolReaderFactory;
|
||||
import net.sf.briar.api.protocol.Request;
|
||||
import net.sf.briar.api.protocol.SubscriptionUpdate;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
@@ -28,11 +29,12 @@ public class ProtocolModule extends AbstractModule {
|
||||
bind(AuthorFactory.class).to(AuthorFactoryImpl.class);
|
||||
bind(BatchFactory.class).to(BatchFactoryImpl.class);
|
||||
bind(GroupFactory.class).to(GroupFactoryImpl.class);
|
||||
bind(MessageEncoder.class).to(MessageEncoderImpl.class);
|
||||
bind(OfferFactory.class).to(OfferFactoryImpl.class);
|
||||
bind(ProtocolReaderFactory.class).to(ProtocolReaderFactoryImpl.class);
|
||||
bind(RequestFactory.class).to(RequestFactoryImpl.class);
|
||||
bind(SubscriptionFactory.class).to(SubscriptionFactoryImpl.class);
|
||||
bind(TransportFactory.class).to(TransportFactoryImpl.class);
|
||||
bind(MessageEncoder.class).to(MessageEncoderImpl.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.Batch;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
import net.sf.briar.api.protocol.ProtocolReader;
|
||||
import net.sf.briar.api.protocol.ProtocolReaderFactory;
|
||||
import net.sf.briar.api.protocol.Request;
|
||||
import net.sf.briar.api.protocol.SubscriptionUpdate;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.ReaderFactory;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
class ProtocolReaderFactoryImpl implements ProtocolReaderFactory {
|
||||
|
||||
private final ReaderFactory readerFactory;
|
||||
private final Provider<ObjectReader<Ack>> ackProvider;
|
||||
private final Provider<ObjectReader<Batch>> batchProvider;
|
||||
private final Provider<ObjectReader<Offer>> offerProvider;
|
||||
private final Provider<ObjectReader<Request>> requestProvider;
|
||||
private final Provider<ObjectReader<SubscriptionUpdate>> subscriptionProvider;
|
||||
private final Provider<ObjectReader<TransportUpdate>> transportProvider;
|
||||
|
||||
@Inject
|
||||
ProtocolReaderFactoryImpl(ReaderFactory readerFactory,
|
||||
Provider<ObjectReader<Ack>> ackProvider,
|
||||
Provider<ObjectReader<Batch>> batchProvider,
|
||||
Provider<ObjectReader<Offer>> offerProvider,
|
||||
Provider<ObjectReader<Request>> requestProvider,
|
||||
Provider<ObjectReader<SubscriptionUpdate>> subscriptionProvider,
|
||||
Provider<ObjectReader<TransportUpdate>> transportProvider) {
|
||||
this.readerFactory = readerFactory;
|
||||
this.ackProvider = ackProvider;
|
||||
this.batchProvider = batchProvider;
|
||||
this.offerProvider = offerProvider;
|
||||
this.requestProvider = requestProvider;
|
||||
this.subscriptionProvider = subscriptionProvider;
|
||||
this.transportProvider = transportProvider;
|
||||
}
|
||||
|
||||
public ProtocolReader createProtocolReader(InputStream in) {
|
||||
return new ProtocolReaderImpl(in, readerFactory, ackProvider.get(),
|
||||
batchProvider.get(), offerProvider.get(), requestProvider.get(),
|
||||
subscriptionProvider.get(), transportProvider.get());
|
||||
}
|
||||
}
|
||||
85
components/net/sf/briar/protocol/ProtocolReaderImpl.java
Normal file
85
components/net/sf/briar/protocol/ProtocolReaderImpl.java
Normal file
@@ -0,0 +1,85 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.Batch;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
import net.sf.briar.api.protocol.ProtocolReader;
|
||||
import net.sf.briar.api.protocol.Request;
|
||||
import net.sf.briar.api.protocol.SubscriptionUpdate;
|
||||
import net.sf.briar.api.protocol.Tags;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
import net.sf.briar.api.serial.ReaderFactory;
|
||||
|
||||
class ProtocolReaderImpl implements ProtocolReader {
|
||||
|
||||
private final Reader reader;
|
||||
|
||||
ProtocolReaderImpl(InputStream in, ReaderFactory readerFactory,
|
||||
ObjectReader<Ack> ackReader, ObjectReader<Batch> batchReader,
|
||||
ObjectReader<Offer> offerReader,
|
||||
ObjectReader<Request> requestReader,
|
||||
ObjectReader<SubscriptionUpdate> subscriptionReader,
|
||||
ObjectReader<TransportUpdate> transportReader) {
|
||||
reader = readerFactory.createReader(in);
|
||||
reader.addObjectReader(Tags.ACK, ackReader);
|
||||
reader.addObjectReader(Tags.BATCH, batchReader);
|
||||
reader.addObjectReader(Tags.OFFER, offerReader);
|
||||
reader.addObjectReader(Tags.REQUEST, requestReader);
|
||||
reader.addObjectReader(Tags.SUBSCRIPTIONS, subscriptionReader);
|
||||
reader.addObjectReader(Tags.TRANSPORTS, transportReader);
|
||||
}
|
||||
|
||||
public boolean hasAck() throws IOException {
|
||||
return reader.hasUserDefined(Tags.ACK);
|
||||
}
|
||||
|
||||
public Ack readAck() throws IOException {
|
||||
return reader.readUserDefined(Tags.ACK, Ack.class);
|
||||
}
|
||||
|
||||
public boolean hasBatch() throws IOException {
|
||||
return reader.hasUserDefined(Tags.BATCH);
|
||||
}
|
||||
|
||||
public Batch readBatch() throws IOException {
|
||||
return reader.readUserDefined(Tags.BATCH, Batch.class);
|
||||
}
|
||||
|
||||
public boolean hasOffer() throws IOException {
|
||||
return reader.hasUserDefined(Tags.OFFER);
|
||||
}
|
||||
|
||||
public Offer readOffer() throws IOException {
|
||||
return reader.readUserDefined(Tags.OFFER, Offer.class);
|
||||
}
|
||||
|
||||
public boolean hasRequest() throws IOException {
|
||||
return reader.hasUserDefined(Tags.REQUEST);
|
||||
}
|
||||
|
||||
public Request readRequest() throws IOException {
|
||||
return reader.readUserDefined(Tags.REQUEST, Request.class);
|
||||
}
|
||||
|
||||
public boolean hasSubscriptionUpdate() throws IOException {
|
||||
return reader.hasUserDefined(Tags.SUBSCRIPTIONS);
|
||||
}
|
||||
|
||||
public SubscriptionUpdate readSubscriptionUpdate() throws IOException {
|
||||
return reader.readUserDefined(Tags.SUBSCRIPTIONS,
|
||||
SubscriptionUpdate.class);
|
||||
}
|
||||
|
||||
public boolean hasTransportUpdate() throws IOException {
|
||||
return reader.hasUserDefined(Tags.TRANSPORTS);
|
||||
}
|
||||
|
||||
public TransportUpdate readTransportUpdate() throws IOException {
|
||||
return reader.readUserDefined(Tags.TRANSPORTS, TransportUpdate.class);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,10 @@ interface PacketDecrypter {
|
||||
/** Returns the input stream from which packets should be read. */
|
||||
InputStream getInputStream();
|
||||
|
||||
/** Reads, decrypts and returns a tag from the underlying input stream. */
|
||||
/**
|
||||
* Reads, decrypts and returns a tag from the underlying input stream.
|
||||
* Returns null if the end of the input stream is reached before any bytes
|
||||
* are read.
|
||||
*/
|
||||
byte[] readTag() throws IOException;
|
||||
}
|
||||
|
||||
@@ -54,9 +54,11 @@ class PacketDecrypterImpl extends FilterInputStream implements PacketDecrypter {
|
||||
bufOff = bufLen = 0;
|
||||
while(offset < tag.length) {
|
||||
int read = in.read(tag, offset, tag.length - offset);
|
||||
if(read == -1) throw new EOFException();
|
||||
if(read == -1) break;
|
||||
offset += read;
|
||||
}
|
||||
if(offset == 0) return null; // EOF between packets is acceptable
|
||||
if(offset < tag.length) throw new EOFException();
|
||||
betweenPackets = false;
|
||||
try {
|
||||
byte[] decryptedTag = tagCipher.doFinal(tag);
|
||||
|
||||
@@ -8,47 +8,18 @@ import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.Batch;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
import net.sf.briar.api.protocol.Request;
|
||||
import net.sf.briar.api.protocol.SubscriptionUpdate;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.ReaderFactory;
|
||||
import net.sf.briar.api.transport.PacketReader;
|
||||
import net.sf.briar.api.transport.PacketReaderFactory;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
class PacketReaderFactoryImpl implements PacketReaderFactory {
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final ReaderFactory readerFactory;
|
||||
private final Provider<ObjectReader<Ack>> ackProvider;
|
||||
private final Provider<ObjectReader<Batch>> batchProvider;
|
||||
private final Provider<ObjectReader<Offer>> offerProvider;
|
||||
private final Provider<ObjectReader<Request>> requestProvider;
|
||||
private final Provider<ObjectReader<SubscriptionUpdate>> subscriptionProvider;
|
||||
private final Provider<ObjectReader<TransportUpdate>> transportProvider;
|
||||
|
||||
@Inject
|
||||
PacketReaderFactoryImpl(CryptoComponent crypto, ReaderFactory readerFactory,
|
||||
Provider<ObjectReader<Ack>> ackProvider,
|
||||
Provider<ObjectReader<Batch>> batchProvider,
|
||||
Provider<ObjectReader<Offer>> offerProvider,
|
||||
Provider<ObjectReader<Request>> requestProvider,
|
||||
Provider<ObjectReader<SubscriptionUpdate>> subscriptionProvider,
|
||||
Provider<ObjectReader<TransportUpdate>> transportProvider) {
|
||||
PacketReaderFactoryImpl(CryptoComponent crypto) {
|
||||
this.crypto = crypto;
|
||||
this.readerFactory = readerFactory;
|
||||
this.ackProvider = ackProvider;
|
||||
this.batchProvider = batchProvider;
|
||||
this.offerProvider = offerProvider;
|
||||
this.requestProvider = requestProvider;
|
||||
this.subscriptionProvider = subscriptionProvider;
|
||||
this.transportProvider = transportProvider;
|
||||
}
|
||||
|
||||
public PacketReader createPacketReader(byte[] firstTag, InputStream in,
|
||||
@@ -66,9 +37,6 @@ class PacketReaderFactoryImpl implements PacketReaderFactory {
|
||||
}
|
||||
PacketDecrypter decrypter = new PacketDecrypterImpl(firstTag, in,
|
||||
tagCipher, packetCipher, tagKey, packetKey);
|
||||
return new PacketReaderImpl(firstTag, readerFactory, ackProvider.get(),
|
||||
batchProvider.get(), offerProvider.get(), requestProvider.get(),
|
||||
subscriptionProvider.get(), transportProvider.get(),
|
||||
decrypter, mac, transportId, connection);
|
||||
return new PacketReaderImpl(decrypter, mac, transportId, connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.Batch;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
import net.sf.briar.api.protocol.Request;
|
||||
import net.sf.briar.api.protocol.SubscriptionUpdate;
|
||||
import net.sf.briar.api.protocol.Tags;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.serial.FormatException;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
import net.sf.briar.api.serial.ReaderFactory;
|
||||
import net.sf.briar.api.transport.PacketReader;
|
||||
|
||||
class PacketReaderImpl implements PacketReader {
|
||||
class PacketReaderImpl extends FilterInputStream implements PacketReader {
|
||||
|
||||
private final Reader reader;
|
||||
private final PacketDecrypter decrypter;
|
||||
private final Mac mac;
|
||||
private final int macLength, transportId;
|
||||
@@ -30,23 +21,9 @@ class PacketReaderImpl implements PacketReader {
|
||||
private long packet = 0L;
|
||||
private boolean betweenPackets = true;
|
||||
|
||||
PacketReaderImpl(byte[] firstTag, ReaderFactory readerFactory,
|
||||
ObjectReader<Ack> ackReader, ObjectReader<Batch> batchReader,
|
||||
ObjectReader<Offer> offerReader,
|
||||
ObjectReader<Request> requestReader,
|
||||
ObjectReader<SubscriptionUpdate> subscriptionReader,
|
||||
ObjectReader<TransportUpdate> transportReader,
|
||||
PacketDecrypter decrypter, Mac mac, int transportId,
|
||||
PacketReaderImpl(PacketDecrypter decrypter, Mac mac, int transportId,
|
||||
long connection) {
|
||||
InputStream in = decrypter.getInputStream();
|
||||
reader = readerFactory.createReader(in);
|
||||
reader.addObjectReader(Tags.ACK, ackReader);
|
||||
reader.addObjectReader(Tags.BATCH, batchReader);
|
||||
reader.addObjectReader(Tags.OFFER, offerReader);
|
||||
reader.addObjectReader(Tags.REQUEST, requestReader);
|
||||
reader.addObjectReader(Tags.SUBSCRIPTIONS, subscriptionReader);
|
||||
reader.addObjectReader(Tags.TRANSPORTS, transportReader);
|
||||
reader.addConsumer(new MacConsumer(mac));
|
||||
super(decrypter.getInputStream());
|
||||
this.decrypter = decrypter;
|
||||
this.mac = mac;
|
||||
macLength = mac.getMacLength();
|
||||
@@ -54,32 +31,36 @@ class PacketReaderImpl implements PacketReader {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
public boolean hasAck() throws IOException {
|
||||
public InputStream getInputStream() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void finishPacket() throws IOException, GeneralSecurityException {
|
||||
if(!betweenPackets) readMac();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
return reader.hasUserDefined(Tags.ACK);
|
||||
int i = in.read();
|
||||
if(i != -1) mac.update((byte) i);
|
||||
return i;
|
||||
}
|
||||
|
||||
private void readTag() throws IOException {
|
||||
assert betweenPackets;
|
||||
if(packet > Constants.MAX_32_BIT_UNSIGNED)
|
||||
throw new IllegalStateException();
|
||||
byte[] tag = decrypter.readTag();
|
||||
if(!TagDecoder.decodeTag(tag, transportId, connection, packet))
|
||||
throw new FormatException();
|
||||
mac.update(tag);
|
||||
packet++;
|
||||
betweenPackets = false;
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
public Ack readAck() throws IOException {
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
Ack a = reader.readUserDefined(Tags.ACK, Ack.class);
|
||||
readMac();
|
||||
betweenPackets = true;
|
||||
return a;
|
||||
int i = in.read(b, off, len);
|
||||
if(i != -1) mac.update(b, off, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
private void readMac() throws IOException {
|
||||
private void readMac() throws IOException, GeneralSecurityException {
|
||||
byte[] expectedMac = mac.doFinal();
|
||||
byte[] actualMac = new byte[macLength];
|
||||
InputStream in = decrypter.getInputStream();
|
||||
@@ -89,74 +70,22 @@ class PacketReaderImpl implements PacketReader {
|
||||
if(read == -1) break;
|
||||
offset += read;
|
||||
}
|
||||
if(offset < macLength) throw new FormatException();
|
||||
if(!Arrays.equals(expectedMac, actualMac)) throw new FormatException();
|
||||
}
|
||||
|
||||
public boolean hasBatch() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
return reader.hasUserDefined(Tags.BATCH);
|
||||
}
|
||||
|
||||
public Batch readBatch() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
Batch b = reader.readUserDefined(Tags.BATCH, Batch.class);
|
||||
readMac();
|
||||
if(offset < macLength) throw new GeneralSecurityException();
|
||||
if(!Arrays.equals(expectedMac, actualMac))
|
||||
throw new GeneralSecurityException();
|
||||
betweenPackets = true;
|
||||
return b;
|
||||
}
|
||||
|
||||
public boolean hasOffer() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
return reader.hasUserDefined(Tags.OFFER);
|
||||
}
|
||||
|
||||
public Offer readOffer() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
Offer o = reader.readUserDefined(Tags.OFFER, Offer.class);
|
||||
readMac();
|
||||
betweenPackets = true;
|
||||
return o;
|
||||
}
|
||||
|
||||
public boolean hasRequest() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
return reader.hasUserDefined(Tags.REQUEST);
|
||||
}
|
||||
|
||||
public Request readRequest() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
Request r = reader.readUserDefined(Tags.REQUEST, Request.class);
|
||||
readMac();
|
||||
betweenPackets = true;
|
||||
return r;
|
||||
}
|
||||
|
||||
public boolean hasSubscriptionUpdate() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
return reader.hasUserDefined(Tags.SUBSCRIPTIONS);
|
||||
}
|
||||
|
||||
public SubscriptionUpdate readSubscriptionUpdate() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
SubscriptionUpdate s = reader.readUserDefined(Tags.SUBSCRIPTIONS,
|
||||
SubscriptionUpdate.class);
|
||||
readMac();
|
||||
betweenPackets = true;
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean hasTransportUpdate() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
return reader.hasUserDefined(Tags.TRANSPORTS);
|
||||
}
|
||||
|
||||
public TransportUpdate readTransportUpdate() throws IOException {
|
||||
if(betweenPackets) readTag();
|
||||
TransportUpdate t = reader.readUserDefined(Tags.TRANSPORTS,
|
||||
TransportUpdate.class);
|
||||
readMac();
|
||||
betweenPackets = true;
|
||||
return t;
|
||||
private void readTag() throws IOException {
|
||||
assert betweenPackets;
|
||||
if(packet > Constants.MAX_32_BIT_UNSIGNED)
|
||||
throw new IllegalStateException();
|
||||
byte[] tag = decrypter.readTag();
|
||||
if(tag == null) return; // EOF
|
||||
if(!TagDecoder.decodeTag(tag, transportId, connection, packet))
|
||||
throw new FormatException();
|
||||
mac.update(tag);
|
||||
packet++;
|
||||
betweenPackets = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class PacketWriterImpl extends FilterOutputStream implements PacketWriter {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void nextPacket() throws IOException {
|
||||
public void finishPacket() throws IOException {
|
||||
if(!betweenPackets) writeMac();
|
||||
}
|
||||
|
||||
@@ -50,9 +50,7 @@ class PacketWriterImpl extends FilterOutputStream implements PacketWriter {
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
if(betweenPackets) writeTag();
|
||||
out.write(b);
|
||||
mac.update(b);
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user