mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 19:59:05 +01:00
Split transport identifiers into two: TransportId (globally unique)
and TransportIndex (locally unique). This is the first step towards forward secrecy. Also removed the Writable interface and unnecessary user-defined types, moved various constants to ProtocolConstants and renamed some classes.
This commit is contained in:
@@ -7,7 +7,6 @@ import java.util.Map;
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.Rating;
|
||||
import net.sf.briar.api.TransportConfig;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.MessageHeader;
|
||||
@@ -18,6 +17,9 @@ import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.GroupId;
|
||||
import net.sf.briar.api.protocol.Message;
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
import net.sf.briar.api.protocol.Transport;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.transport.ConnectionWindow;
|
||||
|
||||
/**
|
||||
@@ -78,14 +80,12 @@ interface Database<T> {
|
||||
void addBatchToAck(T txn, ContactId c, BatchId b) throws DbException;
|
||||
|
||||
/**
|
||||
* Adds a new contact to the database with the given transport properties
|
||||
* and secret, and returns an ID for the contact.
|
||||
* Adds a new contact to the database with the given secret and returns an
|
||||
* ID for the contact.
|
||||
* <p>
|
||||
* Locking: contact write, transport write.
|
||||
* Locking: contact write.
|
||||
*/
|
||||
ContactId addContact(T txn,
|
||||
Map<TransportId, TransportProperties> transports, byte[] secret)
|
||||
throws DbException;
|
||||
ContactId addContact(T txn, byte[] secret) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns false if the given message is already in the database. Otherwise
|
||||
@@ -118,6 +118,14 @@ interface Database<T> {
|
||||
*/
|
||||
void addSubscription(T txn, Group g) throws DbException;
|
||||
|
||||
/**
|
||||
* Allocates and returns a local index for the given transport. Returns
|
||||
* null if all indices have been allocated.
|
||||
* <p>
|
||||
* Locking: transport write.
|
||||
*/
|
||||
TransportIndex addTransport(T txn, TransportId t) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given contact.
|
||||
* <p>
|
||||
@@ -179,7 +187,7 @@ interface Database<T> {
|
||||
* <p>
|
||||
* Locking: contact read, window write.
|
||||
*/
|
||||
long getConnectionNumber(T txn, ContactId c, TransportId t)
|
||||
long getConnectionNumber(T txn, ContactId c, TransportIndex i)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -188,7 +196,7 @@ interface Database<T> {
|
||||
* <p>
|
||||
* Locking: contact read, window read.
|
||||
*/
|
||||
ConnectionWindow getConnectionWindow(T txn, ContactId c, TransportId t)
|
||||
ConnectionWindow getConnectionWindow(T txn, ContactId c, TransportIndex i)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
@@ -216,6 +224,14 @@ interface Database<T> {
|
||||
*/
|
||||
MessageId getGroupMessageParent(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the local index for the given transport, or null if no index
|
||||
* has been allocated.
|
||||
* <p>
|
||||
* Locking: transport read.
|
||||
*/
|
||||
TransportIndex getLocalIndex(T txn, TransportId t) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the local transport properties for the given transport.
|
||||
* <p>
|
||||
@@ -225,12 +241,11 @@ interface Database<T> {
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all local transport properties.
|
||||
* Returns all local transports.
|
||||
* <p>
|
||||
* Locking: transport read.
|
||||
*/
|
||||
Map<TransportId, TransportProperties> getLocalTransports(T txn)
|
||||
throws DbException;
|
||||
Collection<Transport> getLocalTransports(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the IDs of any batches sent to the given contact that should now
|
||||
@@ -312,6 +327,15 @@ interface Database<T> {
|
||||
*/
|
||||
boolean getRead(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the given contact's index for the given transport, or null if
|
||||
* the contact does not support the transport.
|
||||
* <p>
|
||||
* Locking: contact read, window read.
|
||||
*/
|
||||
TransportIndex getRemoteIndex(T txn, ContactId c, TransportId t)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all remote properties for the given transport.
|
||||
* <p>
|
||||
@@ -456,7 +480,7 @@ interface Database<T> {
|
||||
* Removes a contact (and all associated state) from the database.
|
||||
* <p>
|
||||
* Locking: contact write, message write, messageFlag write,
|
||||
* messageStatus write, subscription write, transport write.
|
||||
* messageStatus write, subscription write, transport write, window write.
|
||||
*/
|
||||
void removeContact(T txn, ContactId c) throws DbException;
|
||||
|
||||
@@ -501,7 +525,7 @@ interface Database<T> {
|
||||
* <p>
|
||||
* Locking: contact read, window write.
|
||||
*/
|
||||
void setConnectionWindow(T txn, ContactId c, TransportId t,
|
||||
void setConnectionWindow(T txn, ContactId c, TransportIndex i,
|
||||
ConnectionWindow w) throws DbException;
|
||||
|
||||
/**
|
||||
@@ -591,15 +615,13 @@ interface Database<T> {
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the transport properties for the given contact, replacing any
|
||||
* existing properties unless the existing properties have a newer
|
||||
* timestamp.
|
||||
* Sets the transports for the given contact, replacing any existing
|
||||
* transports unless the existing transports have a newer timestamp.
|
||||
* <p>
|
||||
* Locking: contact read, transport write.
|
||||
*/
|
||||
void setTransports(T txn, ContactId c,
|
||||
Map<TransportId, TransportProperties> transports, long timestamp)
|
||||
throws DbException;
|
||||
void setTransports(T txn, ContactId c, Collection<Transport> transports,
|
||||
long timestamp) throws DbException;
|
||||
|
||||
/**
|
||||
* Records the time at which the local transports were last modified.
|
||||
|
||||
@@ -23,7 +23,6 @@ import net.sf.briar.api.Bytes;
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.Rating;
|
||||
import net.sf.briar.api.TransportConfig;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
@@ -35,10 +34,12 @@ import net.sf.briar.api.db.event.ContactAddedEvent;
|
||||
import net.sf.briar.api.db.event.ContactRemovedEvent;
|
||||
import net.sf.briar.api.db.event.DatabaseEvent;
|
||||
import net.sf.briar.api.db.event.DatabaseListener;
|
||||
import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent;
|
||||
import net.sf.briar.api.db.event.MessagesAddedEvent;
|
||||
import net.sf.briar.api.db.event.RatingChangedEvent;
|
||||
import net.sf.briar.api.db.event.RemoteTransportsUpdatedEvent;
|
||||
import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent;
|
||||
import net.sf.briar.api.db.event.TransportsUpdatedEvent;
|
||||
import net.sf.briar.api.db.event.TransportAddedEvent;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.AuthorId;
|
||||
import net.sf.briar.api.protocol.Batch;
|
||||
@@ -49,6 +50,9 @@ import net.sf.briar.api.protocol.Message;
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
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.TransportIndex;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.protocol.writers.AckWriter;
|
||||
import net.sf.briar.api.protocol.writers.BatchWriter;
|
||||
@@ -131,27 +135,19 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public ContactId addContact(
|
||||
Map<TransportId, TransportProperties> transports, byte[] secret)
|
||||
throws DbException {
|
||||
public ContactId addContact(byte[] secret) throws DbException {
|
||||
if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact");
|
||||
ContactId c;
|
||||
contactLock.writeLock().lock();
|
||||
try {
|
||||
transportLock.writeLock().lock();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
c = db.addContact(txn, transports, secret);
|
||||
db.commitTransaction(txn);
|
||||
if(LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("Added contact " + c);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
transportLock.writeLock().unlock();
|
||||
c = db.addContact(txn, secret);
|
||||
db.commitTransaction(txn);
|
||||
if(LOG.isLoggable(Level.FINE)) LOG.fine("Added contact " + c);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
contactLock.writeLock().unlock();
|
||||
@@ -370,6 +366,26 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public TransportIndex addTransport(TransportId t) throws DbException {
|
||||
TransportIndex i;
|
||||
transportLock.writeLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
i = db.addTransport(txn, t);
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
transportLock.writeLock().unlock();
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(i != null) callListeners(new TransportAddedEvent(t));
|
||||
return i;
|
||||
}
|
||||
|
||||
public boolean generateAck(ContactId c, AckWriter a) throws DbException,
|
||||
IOException {
|
||||
contactLock.readLock().lock();
|
||||
@@ -630,7 +646,7 @@ DatabaseCleaner.Callback {
|
||||
|
||||
public void generateTransportUpdate(ContactId c, TransportWriter t)
|
||||
throws DbException, IOException {
|
||||
Map<TransportId, TransportProperties> transports = null;
|
||||
Collection<Transport> transports = null;
|
||||
long timestamp = 0L;
|
||||
contactLock.readLock().lock();
|
||||
try {
|
||||
@@ -683,7 +699,7 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public long getConnectionNumber(ContactId c, TransportId t)
|
||||
public long getConnectionNumber(ContactId c, TransportIndex i)
|
||||
throws DbException {
|
||||
contactLock.readLock().lock();
|
||||
try {
|
||||
@@ -692,7 +708,7 @@ DatabaseCleaner.Callback {
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
long outgoing = db.getConnectionNumber(txn, c, t);
|
||||
long outgoing = db.getConnectionNumber(txn, c, i);
|
||||
db.commitTransaction(txn);
|
||||
return outgoing;
|
||||
} catch(DbException e) {
|
||||
@@ -707,7 +723,7 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectionWindow getConnectionWindow(ContactId c, TransportId t)
|
||||
public ConnectionWindow getConnectionWindow(ContactId c, TransportIndex i)
|
||||
throws DbException {
|
||||
contactLock.readLock().lock();
|
||||
try {
|
||||
@@ -716,7 +732,7 @@ DatabaseCleaner.Callback {
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
ConnectionWindow w = db.getConnectionWindow(txn, c, t);
|
||||
ConnectionWindow w = db.getConnectionWindow(txn, c, i);
|
||||
db.commitTransaction(txn);
|
||||
return w;
|
||||
} catch(DbException e) {
|
||||
@@ -748,6 +764,23 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public TransportIndex getLocalIndex(TransportId t) throws DbException {
|
||||
transportLock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
TransportIndex i = db.getLocalIndex(txn, t);
|
||||
db.commitTransaction(txn);
|
||||
return i;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
transportLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public TransportProperties getLocalProperties(TransportId t)
|
||||
throws DbException {
|
||||
transportLock.readLock().lock();
|
||||
@@ -766,14 +799,12 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<TransportId, TransportProperties> getLocalTransports()
|
||||
throws DbException {
|
||||
public Collection<Transport> getLocalTransports() throws DbException {
|
||||
transportLock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<TransportId, TransportProperties> transports =
|
||||
db.getLocalTransports(txn);
|
||||
Collection<Transport> transports = db.getLocalTransports(txn);
|
||||
db.commitTransaction(txn);
|
||||
return transports;
|
||||
} catch(DbException e) {
|
||||
@@ -826,6 +857,30 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public TransportIndex getRemoteIndex(ContactId c, TransportId t)
|
||||
throws DbException {
|
||||
contactLock.readLock().lock();
|
||||
try {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
transportLock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
TransportIndex i = db.getRemoteIndex(txn, c, t);
|
||||
db.commitTransaction(txn);
|
||||
return i;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
transportLock.readLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
contactLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<ContactId, TransportProperties> getRemoteProperties(
|
||||
TransportId t) throws DbException {
|
||||
contactLock.readLock().lock();
|
||||
@@ -1135,6 +1190,8 @@ DatabaseCleaner.Callback {
|
||||
} finally {
|
||||
contactLock.readLock().unlock();
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
callListeners(new SubscriptionsUpdatedEvent(Collections.singleton(c)));
|
||||
}
|
||||
|
||||
public void receiveTransportUpdate(ContactId c, TransportUpdate t)
|
||||
@@ -1147,8 +1204,7 @@ DatabaseCleaner.Callback {
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<TransportId, TransportProperties> transports =
|
||||
t.getTransports();
|
||||
Collection<Transport> transports = t.getTransports();
|
||||
db.setTransports(txn, c, transports, t.getTimestamp());
|
||||
if(LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("Received " + transports.size()
|
||||
@@ -1164,6 +1220,8 @@ DatabaseCleaner.Callback {
|
||||
} finally {
|
||||
contactLock.readLock().unlock();
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
callListeners(new RemoteTransportsUpdatedEvent(c));
|
||||
}
|
||||
|
||||
public void removeContact(ContactId c) throws DbException {
|
||||
@@ -1180,13 +1238,18 @@ DatabaseCleaner.Callback {
|
||||
try {
|
||||
transportLock.writeLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
windowLock.writeLock().lock();
|
||||
try {
|
||||
db.removeContact(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
db.removeContact(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
windowLock.writeLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
transportLock.writeLock().unlock();
|
||||
@@ -1227,7 +1290,7 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public void setConnectionWindow(ContactId c, TransportId t,
|
||||
public void setConnectionWindow(ContactId c, TransportIndex i,
|
||||
ConnectionWindow w) throws DbException {
|
||||
contactLock.readLock().lock();
|
||||
try {
|
||||
@@ -1236,7 +1299,7 @@ DatabaseCleaner.Callback {
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
db.setConnectionWindow(txn, c, t, w);
|
||||
db.setConnectionWindow(txn, c, i, w);
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
@@ -1270,7 +1333,7 @@ DatabaseCleaner.Callback {
|
||||
transportLock.writeLock().unlock();
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(changed) callListeners(new TransportsUpdatedEvent());
|
||||
if(changed) callListeners(new LocalTransportsUpdatedEvent());
|
||||
}
|
||||
|
||||
public void setRating(AuthorId a, Rating r) throws DbException {
|
||||
@@ -1430,6 +1493,7 @@ DatabaseCleaner.Callback {
|
||||
} finally {
|
||||
subscriptionLock.writeLock().unlock();
|
||||
}
|
||||
// Listeners will be notified when the group's visibility is set
|
||||
}
|
||||
|
||||
public void unsubscribe(GroupId g) throws DbException {
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.util.logging.Logger;
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.Rating;
|
||||
import net.sf.briar.api.TransportConfig;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.MessageHeader;
|
||||
@@ -32,6 +31,10 @@ import net.sf.briar.api.protocol.GroupFactory;
|
||||
import net.sf.briar.api.protocol.GroupId;
|
||||
import net.sf.briar.api.protocol.Message;
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.Transport;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.transport.ConnectionWindow;
|
||||
import net.sf.briar.api.transport.ConnectionWindowFactory;
|
||||
import net.sf.briar.util.FileUtils;
|
||||
@@ -169,38 +172,56 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
private static final String INDEX_STATUSES_BY_CONTACT =
|
||||
"CREATE INDEX statusesByContact ON statuses (contactId)";
|
||||
|
||||
private static final String CREATE_TRANSPORTS =
|
||||
"CREATE TABLE transports"
|
||||
+ " (transportId HASH NOT NULL,"
|
||||
+ " index COUNTER,"
|
||||
+ " UNIQUE(transportId),"
|
||||
+ " PRIMARY KEY (transportId, index))";
|
||||
|
||||
private static final String CREATE_TRANSPORT_CONFIGS =
|
||||
"CREATE TABLE transportConfigs"
|
||||
+ " (transportId HASH NOT NULL,"
|
||||
+ " key VARCHAR NOT NULL,"
|
||||
+ " value VARCHAR NOT NULL,"
|
||||
+ " PRIMARY KEY (transportId, key))";
|
||||
|
||||
private static final String CREATE_TRANSPORT_PROPS =
|
||||
"CREATE TABLE transportProperties"
|
||||
+ " (transportId HASH NOT NULL,"
|
||||
+ " key VARCHAR NOT NULL,"
|
||||
+ " value VARCHAR NOT NULL,"
|
||||
+ " PRIMARY KEY (transportId, key))";
|
||||
|
||||
private static final String CREATE_CONTACT_TRANSPORTS =
|
||||
"CREATE TABLE contactTransports"
|
||||
+ " (contactId INT NOT NULL,"
|
||||
+ " transportId INT NOT NULL,"
|
||||
+ " transportId HASH NOT NULL,"
|
||||
+ " index INT NOT NULL,"
|
||||
+ " UNIQUE (contactId, transportId),"
|
||||
+ " UNIQUE (contactId, index),"
|
||||
+ " PRIMARY KEY (contactId, transportId, index),"
|
||||
+ " FOREIGN KEY (contactId) REFERENCES contacts (contactId)"
|
||||
+ " ON DELETE CASCADE)";
|
||||
|
||||
private static final String CREATE_CONTACT_TRANSPORT_PROPS =
|
||||
"CREATE TABLE contactTransportProperties"
|
||||
+ " (contactId INT NOT NULL,"
|
||||
+ " transportId HASH NOT NULL,"
|
||||
+ " key VARCHAR NOT NULL,"
|
||||
+ " value VARCHAR NOT NULL,"
|
||||
+ " PRIMARY KEY (contactId, transportId, key),"
|
||||
+ " FOREIGN KEY (contactId) REFERENCES contacts (contactId)"
|
||||
+ " ON DELETE CASCADE)";
|
||||
|
||||
private static final String CREATE_TRANSPORTS =
|
||||
"CREATE TABLE transports"
|
||||
+ " (transportId INT NOT NULL,"
|
||||
+ " key VARCHAR NOT NULL,"
|
||||
+ " value VARCHAR NOT NULL,"
|
||||
+ " PRIMARY KEY (transportId, key))";
|
||||
|
||||
private static final String CREATE_TRANSPORT_CONFIG =
|
||||
"CREATE TABLE transportConfig"
|
||||
+ " (transportId INT NOT NULL,"
|
||||
+ " key VARCHAR NOT NULL,"
|
||||
+ " value VARCHAR NOT NULL,"
|
||||
+ " PRIMARY KEY (transportId, key))";
|
||||
|
||||
private static final String CREATE_CONNECTION_WINDOWS =
|
||||
"CREATE TABLE connectionWindows"
|
||||
+ " (contactId INT NOT NULL,"
|
||||
+ " transportId INT NOT NULL,"
|
||||
+ " index INT NOT NULL,"
|
||||
+ " centre BIGINT NOT NULL,"
|
||||
+ " bitmap INT NOT NULL,"
|
||||
+ " outgoing BIGINT NOT NULL,"
|
||||
+ " PRIMARY KEY (contactId, transportId),"
|
||||
+ " PRIMARY KEY (contactId, index),"
|
||||
+ " FOREIGN KEY (contactId) REFERENCES contacts (contactId)"
|
||||
+ " ON DELETE CASCADE)";
|
||||
|
||||
@@ -316,9 +337,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
s.executeUpdate(insertTypeNames(CREATE_STATUSES));
|
||||
s.executeUpdate(INDEX_STATUSES_BY_MESSAGE);
|
||||
s.executeUpdate(INDEX_STATUSES_BY_CONTACT);
|
||||
s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORTS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_TRANSPORTS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_CONFIG));
|
||||
s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_CONFIGS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_PROPS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORTS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORT_PROPS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_CONNECTION_WINDOWS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_SUBSCRIPTION_TIMESTAMPS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_TIMESTAMPS));
|
||||
@@ -478,8 +501,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public ContactId addContact(Connection txn,
|
||||
Map<TransportId, TransportProperties> transports, byte[] secret)
|
||||
public ContactId addContact(Connection txn, byte[] secret)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
@@ -502,29 +524,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
// Store the contact's transport properties
|
||||
sql = "INSERT INTO contactTransports"
|
||||
+ " (contactId, transportId, key, value)"
|
||||
+ " VALUES (?, ?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
int batchSize = 0;
|
||||
for(Entry<TransportId, TransportProperties> e
|
||||
: transports.entrySet()) {
|
||||
ps.setInt(2, e.getKey().getInt());
|
||||
for(Entry<String, String> e1 : e.getValue().entrySet()) {
|
||||
ps.setString(3, e1.getKey());
|
||||
ps.setString(4, e1.getValue());
|
||||
ps.addBatch();
|
||||
batchSize++;
|
||||
}
|
||||
}
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if(batchAffected.length != batchSize) throw new DbStateException();
|
||||
for(int i = 0; i < batchAffected.length; i++) {
|
||||
if(batchAffected[i] != 1) throw new DbStateException();
|
||||
}
|
||||
ps.close();
|
||||
// Initialise the subscription timestamps
|
||||
sql = "INSERT INTO subscriptionTimestamps"
|
||||
+ " (contactId, sent, received, modified)"
|
||||
@@ -693,6 +692,44 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public TransportIndex addTransport(Connection txn, TransportId t)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
// Allocate a new index
|
||||
String sql = "INSERT INTO transports (transportId) VALUES (?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, t.getBytes());
|
||||
int affected = ps.executeUpdate();
|
||||
if(affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
// If the new index is in range, return it
|
||||
sql = "SELECT index FROM transports WHERE transportId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, t.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
if(!rs.next()) throw new DbStateException();
|
||||
int i = rs.getInt(1);
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
if(i < ProtocolConstants.MAX_TRANSPORTS)
|
||||
return new TransportIndex(i);
|
||||
// Too many transports - delete the new index and return null
|
||||
sql = "DELETE FROM transports WHERE transportId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, t.getBytes());
|
||||
affected = ps.executeUpdate();
|
||||
if(affected != 1) throw new DbStateException();
|
||||
return null;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsContact(Connection txn, ContactId c)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -836,10 +873,10 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT key, value FROM transportConfig"
|
||||
String sql = "SELECT key, value FROM transportConfigs"
|
||||
+ " WHERE transportId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, t.getInt());
|
||||
ps.setBytes(1, t.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
TransportConfig c = new TransportConfig();
|
||||
while(rs.next()) c.put(rs.getString(1), rs.getString(2));
|
||||
@@ -854,15 +891,15 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
public long getConnectionNumber(Connection txn, ContactId c,
|
||||
TransportId t) throws DbException {
|
||||
TransportIndex i) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT outgoing FROM connectionWindows"
|
||||
+ " WHERE contactId = ? AND transportId = ?";
|
||||
+ " WHERE contactId = ? AND index = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, t.getInt());
|
||||
ps.setInt(2, i.getInt());
|
||||
rs = ps.executeQuery();
|
||||
if(rs.next()) {
|
||||
// A connection window row exists - update it
|
||||
@@ -871,11 +908,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
rs.close();
|
||||
ps.close();
|
||||
sql = "UPDATE connectionWindows SET outgoing = ?"
|
||||
+ " WHERE contactId = ? AND transportId = ?";
|
||||
+ " WHERE contactId = ? AND index = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setLong(1, outgoing + 1);
|
||||
ps.setInt(2, c.getInt());
|
||||
ps.setInt(3, t.getInt());
|
||||
ps.setInt(3, i.getInt());
|
||||
int affected = ps.executeUpdate();
|
||||
if(affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
@@ -885,11 +922,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
rs.close();
|
||||
ps.close();
|
||||
sql = "INSERT INTO connectionWindows"
|
||||
+ " (contactId, transportId, centre, bitmap, outgoing)"
|
||||
+ " (contactId, index, centre, bitmap, outgoing)"
|
||||
+ " VALUES(?, ?, ZERO(), ZERO(), ZERO())";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, t.getInt());
|
||||
ps.setInt(2, i.getInt());
|
||||
int affected = ps.executeUpdate();
|
||||
if(affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
@@ -903,15 +940,15 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
public ConnectionWindow getConnectionWindow(Connection txn, ContactId c,
|
||||
TransportId t) throws DbException {
|
||||
TransportIndex i) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT centre, bitmap FROM connectionWindows"
|
||||
+ " WHERE contactId = ? AND transportId = ?";
|
||||
+ " WHERE contactId = ? AND index = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, t.getInt());
|
||||
ps.setInt(2, i.getInt());
|
||||
rs = ps.executeQuery();
|
||||
long centre = 0L;
|
||||
int bitmap = 0;
|
||||
@@ -987,15 +1024,39 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public TransportIndex getLocalIndex(Connection txn, TransportId t)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT index FROM transports WHERE transportId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, t.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
TransportIndex index = null;
|
||||
if(rs.next()) {
|
||||
index = new TransportIndex(rs.getInt(1));
|
||||
if(rs.next()) throw new DbStateException();
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
return index;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public TransportProperties getLocalProperties(Connection txn, TransportId t)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT key, value FROM transports"
|
||||
String sql = "SELECT key, value FROM transportProperties"
|
||||
+ " WHERE transportId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, t.getInt());
|
||||
ps.setBytes(1, t.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
TransportProperties p = new TransportProperties();
|
||||
while(rs.next()) p.put(rs.getString(1), rs.getString(2));
|
||||
@@ -1009,26 +1070,31 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<TransportId, TransportProperties> getLocalTransports(
|
||||
Connection txn) throws DbException {
|
||||
public Collection<Transport> getLocalTransports(Connection txn)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT transportId, key, value FROM transports"
|
||||
+ " ORDER BY transportId";
|
||||
String sql = "SELECT transports.transportId, index, key, value"
|
||||
+ " FROM transports LEFT OUTER JOIN transportProperties"
|
||||
+ " ON transports.transportId"
|
||||
+ " = transportProperties.transportId"
|
||||
+ " ORDER BY transports.transportId";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
Map<TransportId, TransportProperties> transports =
|
||||
new HashMap<TransportId, TransportProperties>();
|
||||
TransportProperties p = null;
|
||||
Collection<Transport> transports = new ArrayList<Transport>();
|
||||
TransportId lastId = null;
|
||||
Transport t = null;
|
||||
while(rs.next()) {
|
||||
TransportId id = new TransportId(rs.getInt(1));
|
||||
TransportId id = new TransportId(rs.getBytes(1));
|
||||
if(!id.equals(lastId)) {
|
||||
p = new TransportProperties();
|
||||
transports.put(id, p);
|
||||
t = new Transport(id, new TransportIndex(rs.getInt(2)));
|
||||
transports.add(t);
|
||||
}
|
||||
p.put(rs.getString(2), rs.getString(3));
|
||||
// Key and value may be null due to the left outer join
|
||||
String key = rs.getString(3);
|
||||
String value = rs.getString(4);
|
||||
if(key != null && value != null) t.put(key, value);
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
@@ -1357,21 +1423,48 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public TransportIndex getRemoteIndex(Connection txn, ContactId c,
|
||||
TransportId t) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT index FROM contactTransports"
|
||||
+ " WHERE contactId = ? AND transportId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setBytes(2, t.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
TransportIndex index = null;
|
||||
if(rs.next()) {
|
||||
index = new TransportIndex(rs.getInt(1));
|
||||
if(rs.next()) throw new DbStateException();
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
return index;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<ContactId, TransportProperties> getRemoteProperties(
|
||||
Connection txn, TransportId t) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT contactId, key, value FROM contactTransports"
|
||||
String sql = "SELECT contactId, key, value"
|
||||
+ " FROM contactTransportProperties"
|
||||
+ " WHERE transportId = ?"
|
||||
+ " ORDER BY contactId";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, t.getInt());
|
||||
ps.setBytes(1, t.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
Map<ContactId, TransportProperties> properties =
|
||||
new HashMap<ContactId, TransportProperties>();
|
||||
TransportProperties p = null;
|
||||
ContactId lastId = null;
|
||||
TransportProperties p = null;
|
||||
while(rs.next()) {
|
||||
ContactId id = new ContactId(rs.getInt(1));
|
||||
if(!id.equals(lastId)) {
|
||||
@@ -2034,16 +2127,16 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
// Delete any existing config for the given transport
|
||||
String sql = "DELETE FROM transportConfig WHERE transportId = ?";
|
||||
String sql = "DELETE FROM transportConfigs WHERE transportId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, t.getInt());
|
||||
ps.setBytes(1, t.getBytes());
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
// Store the new config
|
||||
sql = "INSERT INTO transportConfig (transportId, key, value)"
|
||||
sql = "INSERT INTO transportConfigs (transportId, key, value)"
|
||||
+ " VALUES (?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, t.getInt());
|
||||
ps.setBytes(1, t.getBytes());
|
||||
for(Entry<String, String> e : c.entrySet()) {
|
||||
ps.setString(2, e.getKey());
|
||||
ps.setString(3, e.getValue());
|
||||
@@ -2063,15 +2156,15 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
public void setConnectionWindow(Connection txn, ContactId c,
|
||||
TransportId t, ConnectionWindow w) throws DbException {
|
||||
TransportIndex i, ConnectionWindow w) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT NULL FROM connectionWindows"
|
||||
+ " WHERE contactId = ? AND transportId = ?";
|
||||
+ " WHERE contactId = ? AND index = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, t.getInt());
|
||||
ps.setInt(2, i.getInt());
|
||||
rs = ps.executeQuery();
|
||||
boolean found = rs.next();
|
||||
if(rs.next()) throw new DbStateException();
|
||||
@@ -2080,23 +2173,23 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
if(found) {
|
||||
// A connection window row exists - update it
|
||||
sql = "UPDATE connectionWindows SET centre = ?, bitmap = ?"
|
||||
+ " WHERE contactId = ? AND transportId = ?";
|
||||
+ " WHERE contactId = ? AND index = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setLong(1, w.getCentre());
|
||||
ps.setInt(2, w.getBitmap());
|
||||
ps.setInt(3, c.getInt());
|
||||
ps.setInt(4, t.getInt());
|
||||
ps.setInt(4, i.getInt());
|
||||
int affected = ps.executeUpdate();
|
||||
if(affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} else {
|
||||
// No connection window row exists - create one
|
||||
sql = "INSERT INTO connectionWindows"
|
||||
+ " (contactId, transportId, centre, bitmap, outgoing)"
|
||||
+ " (contactId, index, centre, bitmap, outgoing)"
|
||||
+ " VALUES(?, ?, ?, ?, ZERO())";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, t.getInt());
|
||||
ps.setInt(2, i.getInt());
|
||||
ps.setLong(3, w.getCentre());
|
||||
ps.setInt(4, w.getBitmap());
|
||||
int affected = ps.executeUpdate();
|
||||
@@ -2115,16 +2208,17 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
// Delete any existing properties for the given transport
|
||||
String sql = "DELETE FROM transports WHERE transportId = ?";
|
||||
String sql = "DELETE FROM transportProperties"
|
||||
+ " WHERE transportId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, t.getInt());
|
||||
ps.setBytes(1, t.getBytes());
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
// Store the new properties
|
||||
sql = "INSERT INTO transports (transportId, key, value)"
|
||||
sql = "INSERT INTO transportProperties (transportId, key, value)"
|
||||
+ " VALUES (?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, t.getInt());
|
||||
ps.setBytes(1, t.getBytes());
|
||||
for(Entry<String, String> e : p.entrySet()) {
|
||||
ps.setString(2, e.getKey());
|
||||
ps.setString(3, e.getValue());
|
||||
@@ -2504,7 +2598,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
public void setTransports(Connection txn, ContactId c,
|
||||
Map<TransportId, TransportProperties> transports, long timestamp)
|
||||
Collection<Transport> transports, long timestamp)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
@@ -2527,24 +2621,45 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
// Delete any existing transport properties
|
||||
sql = "DELETE FROM contactTransportProperties WHERE contactId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
// Store the new transports
|
||||
sql = "INSERT INTO contactTransports"
|
||||
+ " (contactId, transportId, key, value)"
|
||||
+ " VALUES (?, ?, ?, ?)";
|
||||
+ " (contactId, transportId, index) VALUES (?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
for(Transport t : transports) {
|
||||
ps.setBytes(2, t.getId().getBytes());
|
||||
ps.setInt(3, t.getIndex().getInt());
|
||||
ps.addBatch();
|
||||
}
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if(batchAffected.length != transports.size())
|
||||
throw new DbStateException();
|
||||
for(int i = 0; i < batchAffected.length; i++) {
|
||||
if(batchAffected[i] != 1) throw new DbStateException();
|
||||
}
|
||||
ps.close();
|
||||
// Store the new transport properties
|
||||
sql = "INSERT INTO contactTransportProperties"
|
||||
+ " (contactId, transportId, key, value) VALUES (?, ?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
int batchSize = 0;
|
||||
for(Entry<TransportId, TransportProperties> e
|
||||
: transports.entrySet()) {
|
||||
ps.setInt(2, e.getKey().getInt());
|
||||
for(Entry<String, String> e1 : e.getValue().entrySet()) {
|
||||
for(Transport t : transports) {
|
||||
ps.setBytes(2, t.getId().getBytes());
|
||||
for(Entry<String, String> e1 : t.entrySet()) {
|
||||
ps.setString(3, e1.getKey());
|
||||
ps.setString(4, e1.getValue());
|
||||
ps.addBatch();
|
||||
batchSize++;
|
||||
}
|
||||
}
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
batchAffected = ps.executeBatch();
|
||||
if(batchAffected.length != batchSize) throw new DbStateException();
|
||||
for(int i = 0; i < batchAffected.length; i++) {
|
||||
if(batchAffected[i] != 1) throw new DbStateException();
|
||||
|
||||
@@ -5,15 +5,14 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.invitation.InvitationCallback;
|
||||
import net.sf.briar.api.invitation.InvitationParameters;
|
||||
import net.sf.briar.api.protocol.Transport;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
import net.sf.briar.util.FileUtils;
|
||||
@@ -72,7 +71,7 @@ class InvitationWorker implements Runnable {
|
||||
File invitationDat = new File(dir, "invitation.dat");
|
||||
callback.encryptingFile(invitationDat);
|
||||
// FIXME: Create a real invitation
|
||||
Map<TransportId, TransportProperties> transports;
|
||||
Collection<Transport> transports;
|
||||
try {
|
||||
transports = db.getLocalTransports();
|
||||
} catch(DbException e) {
|
||||
@@ -80,7 +79,7 @@ class InvitationWorker implements Runnable {
|
||||
}
|
||||
FileOutputStream out = new FileOutputStream(invitationDat);
|
||||
Writer w = writerFactory.createWriter(out);
|
||||
w.writeMap(transports);
|
||||
w.writeList(transports);
|
||||
out.flush();
|
||||
out.close();
|
||||
return invitationDat;
|
||||
|
||||
@@ -8,12 +8,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportConfig;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
@@ -26,7 +26,9 @@ import net.sf.briar.api.plugins.PluginManager;
|
||||
import net.sf.briar.api.plugins.StreamPlugin;
|
||||
import net.sf.briar.api.plugins.StreamPluginCallback;
|
||||
import net.sf.briar.api.plugins.StreamPluginFactory;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.transport.BatchTransportReader;
|
||||
import net.sf.briar.api.transport.BatchTransportWriter;
|
||||
import net.sf.briar.api.transport.ConnectionDispatcher;
|
||||
@@ -49,26 +51,32 @@ class PluginManagerImpl implements PluginManager {
|
||||
"net.sf.briar.plugins.socket.SimpleSocketPluginFactory"
|
||||
};
|
||||
|
||||
private final Executor executor;
|
||||
private static final int THREAD_POOL_SIZE = 5;
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final Poller poller;
|
||||
private final ConnectionDispatcher dispatcher;
|
||||
private final UiCallback uiCallback;
|
||||
private final Executor executor;
|
||||
private final List<BatchPlugin> batchPlugins;
|
||||
private final List<StreamPlugin> streamPlugins;
|
||||
|
||||
@Inject
|
||||
PluginManagerImpl(Executor executor, DatabaseComponent db, Poller poller,
|
||||
PluginManagerImpl(DatabaseComponent db, Poller poller,
|
||||
ConnectionDispatcher dispatcher, UiCallback uiCallback) {
|
||||
this.executor = executor;
|
||||
this.db = db;
|
||||
this.poller = poller;
|
||||
this.dispatcher = dispatcher;
|
||||
this.uiCallback = uiCallback;
|
||||
executor = new ScheduledThreadPoolExecutor(THREAD_POOL_SIZE);
|
||||
batchPlugins = new ArrayList<BatchPlugin>();
|
||||
streamPlugins = new ArrayList<StreamPlugin>();
|
||||
}
|
||||
|
||||
public synchronized int getPluginCount() {
|
||||
return batchPlugins.size() + streamPlugins.size();
|
||||
}
|
||||
|
||||
public synchronized int startPlugins() {
|
||||
Set<TransportId> ids = new HashSet<TransportId>();
|
||||
// Instantiate and start the batch plugins
|
||||
@@ -81,8 +89,8 @@ class PluginManagerImpl implements PluginManager {
|
||||
BatchPlugin plugin = factory.createPlugin(executor, callback);
|
||||
if(plugin == null) {
|
||||
if(LOG.isLoggable(Level.INFO))
|
||||
LOG.info(factory.getClass().getSimpleName() +
|
||||
" did not create a plugin");
|
||||
LOG.info(factory.getClass().getSimpleName()
|
||||
+ " did not create a plugin");
|
||||
continue;
|
||||
}
|
||||
TransportId id = plugin.getId();
|
||||
@@ -91,7 +99,14 @@ class PluginManagerImpl implements PluginManager {
|
||||
LOG.warning("Duplicate transport ID: " + id);
|
||||
continue;
|
||||
}
|
||||
callback.setId(id);
|
||||
TransportIndex index = db.getLocalIndex(id);
|
||||
if(index == null) index = db.addTransport(id);
|
||||
if(index == null) {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning("Could not allocate index for ID: " + id);
|
||||
continue;
|
||||
}
|
||||
callback.init(id, index);
|
||||
plugin.start();
|
||||
batchPlugins.add(plugin);
|
||||
} catch(ClassCastException e) {
|
||||
@@ -122,7 +137,14 @@ class PluginManagerImpl implements PluginManager {
|
||||
LOG.warning("Duplicate transport ID: " + id);
|
||||
continue;
|
||||
}
|
||||
callback.setId(id);
|
||||
TransportIndex index = db.getLocalIndex(id);
|
||||
if(index == null) index = db.addTransport(id);
|
||||
if(index == null) {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning("Could not allocate index for ID: " + id);
|
||||
continue;
|
||||
}
|
||||
callback.init(id, index);
|
||||
plugin.start();
|
||||
streamPlugins.add(plugin);
|
||||
} catch(ClassCastException e) {
|
||||
@@ -138,7 +160,7 @@ class PluginManagerImpl implements PluginManager {
|
||||
plugins.addAll(batchPlugins);
|
||||
plugins.addAll(streamPlugins);
|
||||
poller.startPolling(plugins);
|
||||
// Return the number of plugins started
|
||||
// Return the number of plugins successfully started
|
||||
return batchPlugins.size() + streamPlugins.size();
|
||||
}
|
||||
|
||||
@@ -164,17 +186,19 @@ class PluginManagerImpl implements PluginManager {
|
||||
}
|
||||
}
|
||||
streamPlugins.clear();
|
||||
// Return the number of plugins stopped
|
||||
// Return the number of plugins successfully stopped
|
||||
return stopped;
|
||||
}
|
||||
|
||||
private abstract class PluginCallbackImpl implements PluginCallback {
|
||||
|
||||
protected volatile TransportId id = null;
|
||||
protected volatile TransportIndex index = null;
|
||||
|
||||
protected void setId(TransportId id) {
|
||||
assert this.id == null;
|
||||
protected void init(TransportId id, TransportIndex index) {
|
||||
assert this.id == null && this.index == null;
|
||||
this.id = id;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public TransportConfig getConfig() {
|
||||
@@ -219,20 +243,20 @@ class PluginManagerImpl implements PluginManager {
|
||||
|
||||
public void setLocalProperties(TransportProperties p) {
|
||||
assert id != null;
|
||||
if(p.size() > TransportUpdate.MAX_PROPERTIES_PER_PLUGIN) {
|
||||
if(p.size() > ProtocolConstants.MAX_PROPERTIES_PER_TRANSPORT) {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning("Plugin " + id + " set too many properties");
|
||||
return;
|
||||
}
|
||||
for(String s : p.keySet()) {
|
||||
if(s.length() > TransportUpdate.MAX_KEY_OR_VALUE_LENGTH) {
|
||||
if(s.length() > ProtocolConstants.MAX_PROPERTY_LENGTH) {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning("Plugin " + id + " set long key: " + s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for(String s : p.values()) {
|
||||
if(s.length() > TransportUpdate.MAX_KEY_OR_VALUE_LENGTH) {
|
||||
if(s.length() > ProtocolConstants.MAX_PROPERTY_LENGTH) {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning("Plugin " + id + " set long value: " + s);
|
||||
return;
|
||||
@@ -267,8 +291,8 @@ class PluginManagerImpl implements PluginManager {
|
||||
}
|
||||
|
||||
public void writerCreated(ContactId c, BatchTransportWriter w) {
|
||||
assert id != null;
|
||||
dispatcher.dispatchWriter(id, c, w);
|
||||
assert index != null;
|
||||
dispatcher.dispatchWriter(index, c, w);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,8 +306,8 @@ class PluginManagerImpl implements PluginManager {
|
||||
|
||||
public void outgoingConnectionCreated(ContactId c,
|
||||
StreamTransportConnection s) {
|
||||
assert id != null;
|
||||
dispatcher.dispatchOutgoingConnection(id, c, s);
|
||||
assert index != null;
|
||||
dispatcher.dispatchOutgoingConnection(index, c, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,8 +73,6 @@ class PollerImpl implements Poller, Runnable {
|
||||
public int compareTo(PollTime p) {
|
||||
if(time < p.time) return -1;
|
||||
if(time > p.time) return 1;
|
||||
if(plugin.getId().getInt() < p.plugin.getId().getInt()) return -1;
|
||||
if(plugin.getId().getInt() > p.plugin.getId().getInt()) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ import javax.microedition.io.StreamConnection;
|
||||
import javax.microedition.io.StreamConnectionNotifier;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.plugins.StreamPlugin;
|
||||
import net.sf.briar.api.plugins.StreamPluginCallback;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.transport.StreamTransportConnection;
|
||||
import net.sf.briar.plugins.AbstractPlugin;
|
||||
import net.sf.briar.util.OsUtils;
|
||||
@@ -29,7 +29,9 @@ import net.sf.briar.util.StringUtils;
|
||||
|
||||
class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
||||
|
||||
public static final int TRANSPORT_ID = 2;
|
||||
public static final byte[] TRANSPORT_ID =
|
||||
StringUtils.fromHexString("d99c9313c04417dcf22fc60d12a187ea"
|
||||
+ "00a539fd260f08a13a0d8a900cde5e49");
|
||||
|
||||
private static final TransportId id = new TransportId(TRANSPORT_ID);
|
||||
private static final Logger LOG =
|
||||
|
||||
@@ -9,13 +9,16 @@ import java.util.concurrent.Executor;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.plugins.BatchPluginCallback;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.util.StringUtils;
|
||||
|
||||
class RemovableDrivePlugin extends FilePlugin
|
||||
implements RemovableDriveMonitor.Callback {
|
||||
|
||||
public static final int TRANSPORT_ID = 0;
|
||||
public static final byte[] TRANSPORT_ID =
|
||||
StringUtils.fromHexString("7c81bf5c9b1cd557685548c85f976bbd"
|
||||
+ "e633d2418ea2e230e5710fb43c6f8cc0");
|
||||
|
||||
private static final TransportId id = new TransportId(TRANSPORT_ID);
|
||||
private static final Logger LOG =
|
||||
|
||||
@@ -14,14 +14,17 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.plugins.StreamPluginCallback;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.transport.StreamTransportConnection;
|
||||
import net.sf.briar.util.StringUtils;
|
||||
|
||||
class SimpleSocketPlugin extends SocketPlugin {
|
||||
|
||||
public static final int TRANSPORT_ID = 1;
|
||||
public static final byte[] TRANSPORT_ID =
|
||||
StringUtils.fromHexString("58c66d999e492b85065924acfd739d80"
|
||||
+ "c65a62f87e5a4fc6c284f95908b9007d");
|
||||
|
||||
private static final TransportId id = new TransportId(TRANSPORT_ID);
|
||||
private static final Logger LOG =
|
||||
|
||||
@@ -32,8 +32,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
|
||||
protected abstract SocketAddress getLocalSocketAddress();
|
||||
protected abstract SocketAddress getRemoteSocketAddress(ContactId c);
|
||||
|
||||
protected SocketPlugin(Executor executor,
|
||||
StreamPluginCallback callback) {
|
||||
protected SocketPlugin(Executor executor, StreamPluginCallback callback) {
|
||||
super(executor);
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.protocol.Author;
|
||||
import net.sf.briar.api.protocol.AuthorFactory;
|
||||
import net.sf.briar.api.protocol.AuthorId;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
@@ -28,7 +29,9 @@ class AuthorFactoryImpl implements AuthorFactory {
|
||||
throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
Writer w = writerFactory.createWriter(out);
|
||||
new AuthorImpl(null, name, publicKey).writeTo(w);
|
||||
w.writeUserDefinedId(Types.AUTHOR);
|
||||
w.writeString(name);
|
||||
w.writeBytes(publicKey);
|
||||
MessageDigest messageDigest = crypto.getMessageDigest();
|
||||
messageDigest.reset();
|
||||
messageDigest.update(out.toByteArray());
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.protocol.Author;
|
||||
import net.sf.briar.api.protocol.AuthorId;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
class AuthorImpl implements Author {
|
||||
|
||||
@@ -30,10 +26,4 @@ class AuthorImpl implements Author {
|
||||
public byte[] getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public void writeTo(Writer w) throws IOException {
|
||||
w.writeUserDefinedId(Types.AUTHOR);
|
||||
w.writeString(name);
|
||||
w.writeBytes(publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.protocol.Author;
|
||||
import net.sf.briar.api.protocol.AuthorFactory;
|
||||
import net.sf.briar.api.protocol.AuthorId;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
@@ -28,8 +29,8 @@ class AuthorReader implements ObjectReader<Author> {
|
||||
// Read and digest the data
|
||||
r.addConsumer(digesting);
|
||||
r.readUserDefinedId(Types.AUTHOR);
|
||||
String name = r.readString(Author.MAX_NAME_LENGTH);
|
||||
byte[] publicKey = r.readBytes(Author.MAX_PUBLIC_KEY_LENGTH);
|
||||
String name = r.readString(ProtocolConstants.MAX_AUTHOR_NAME_LENGTH);
|
||||
byte[] publicKey = r.readBytes(ProtocolConstants.MAX_PUBLIC_KEY_LENGTH);
|
||||
r.removeConsumer(digesting);
|
||||
// Build and return the author
|
||||
AuthorId id = new AuthorId(messageDigest.digest());
|
||||
|
||||
@@ -8,6 +8,7 @@ import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.GroupFactory;
|
||||
import net.sf.briar.api.protocol.GroupId;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
@@ -27,7 +28,10 @@ class GroupFactoryImpl implements GroupFactory {
|
||||
public Group createGroup(String name, byte[] publicKey) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
Writer w = writerFactory.createWriter(out);
|
||||
new GroupImpl(null, name, publicKey).writeTo(w);
|
||||
w.writeUserDefinedId(Types.GROUP);
|
||||
w.writeString(name);
|
||||
if(publicKey == null) w.writeNull();
|
||||
else w.writeBytes(publicKey);
|
||||
MessageDigest messageDigest = crypto.getMessageDigest();
|
||||
messageDigest.reset();
|
||||
messageDigest.update(out.toByteArray());
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.FormatException;
|
||||
import net.sf.briar.api.protocol.GroupId;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.UniqueId;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
|
||||
class GroupIdReader implements ObjectReader<GroupId> {
|
||||
|
||||
public GroupId readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedId(Types.GROUP_ID);
|
||||
byte[] b = r.readBytes(UniqueId.LENGTH);
|
||||
if(b.length != UniqueId.LENGTH) throw new FormatException();
|
||||
return new GroupId(b);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.GroupId;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
class GroupImpl implements Group {
|
||||
|
||||
@@ -31,13 +27,6 @@ class GroupImpl implements Group {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public void writeTo(Writer w) throws IOException {
|
||||
w.writeUserDefinedId(Types.GROUP);
|
||||
w.writeString(name);
|
||||
if(publicKey == null) w.writeNull();
|
||||
else w.writeBytes(publicKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof Group && id.equals(((Group) o).getId());
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.GroupFactory;
|
||||
import net.sf.briar.api.protocol.GroupId;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
@@ -28,10 +29,10 @@ class GroupReader implements ObjectReader<Group> {
|
||||
// Read and digest the data
|
||||
r.addConsumer(digesting);
|
||||
r.readUserDefinedId(Types.GROUP);
|
||||
String name = r.readString(Group.MAX_NAME_LENGTH);
|
||||
String name = r.readString(ProtocolConstants.MAX_GROUP_NAME_LENGTH);
|
||||
byte[] publicKey = null;
|
||||
if(r.hasNull()) r.readNull();
|
||||
else publicKey = r.readBytes(Group.MAX_PUBLIC_KEY_LENGTH);
|
||||
else publicKey = r.readBytes(ProtocolConstants.MAX_PUBLIC_KEY_LENGTH);
|
||||
r.removeConsumer(digesting);
|
||||
// Build and return the group
|
||||
GroupId id = new GroupId(messageDigest.digest());
|
||||
|
||||
@@ -14,10 +14,12 @@ import net.sf.briar.api.protocol.AuthorId;
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.GroupId;
|
||||
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.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.writers.AuthorWriter;
|
||||
import net.sf.briar.api.protocol.writers.GroupWriter;
|
||||
import net.sf.briar.api.protocol.writers.MessageEncoder;
|
||||
import net.sf.briar.api.serial.Consumer;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
@@ -30,14 +32,19 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
private final SecureRandom random;
|
||||
private final MessageDigest messageDigest;
|
||||
private final WriterFactory writerFactory;
|
||||
private final AuthorWriter authorWriter;
|
||||
private final GroupWriter groupWriter;
|
||||
|
||||
@Inject
|
||||
MessageEncoderImpl(CryptoComponent crypto, WriterFactory writerFactory) {
|
||||
MessageEncoderImpl(CryptoComponent crypto, WriterFactory writerFactory,
|
||||
AuthorWriter authorWriter, GroupWriter groupWriter) {
|
||||
authorSignature = crypto.getSignature();
|
||||
groupSignature = crypto.getSignature();
|
||||
random = crypto.getSecureRandom();
|
||||
messageDigest = crypto.getMessageDigest();
|
||||
this.writerFactory = writerFactory;
|
||||
this.authorWriter = authorWriter;
|
||||
this.groupWriter = groupWriter;
|
||||
}
|
||||
|
||||
public Message encodeMessage(MessageId parent, String subject, byte[] body)
|
||||
@@ -74,9 +81,9 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
if((group == null || group.getPublicKey() == null) !=
|
||||
(groupKey == null))
|
||||
throw new IllegalArgumentException();
|
||||
if(subject.getBytes("UTF-8").length > Message.MAX_SUBJECT_LENGTH)
|
||||
if(subject.getBytes("UTF-8").length > ProtocolConstants.MAX_SUBJECT_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
if(body.length > Message.MAX_BODY_LENGTH)
|
||||
if(body.length > ProtocolConstants.MAX_BODY_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
@@ -102,15 +109,15 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
// Write the message
|
||||
w.writeUserDefinedId(Types.MESSAGE);
|
||||
if(parent == null) w.writeNull();
|
||||
else parent.writeTo(w);
|
||||
else w.writeBytes(parent.getBytes());
|
||||
if(group == null) w.writeNull();
|
||||
else group.writeTo(w);
|
||||
else groupWriter.writeGroup(w, group);
|
||||
if(author == null) w.writeNull();
|
||||
else author.writeTo(w);
|
||||
else authorWriter.writeAuthor(w, author);
|
||||
w.writeString(subject);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
w.writeInt64(timestamp);
|
||||
byte[] salt = new byte[Message.SALT_LENGTH];
|
||||
byte[] salt = new byte[ProtocolConstants.SALT_LENGTH];
|
||||
random.nextBytes(salt);
|
||||
w.writeBytes(salt);
|
||||
w.writeBytes(body);
|
||||
@@ -121,7 +128,7 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
} else {
|
||||
w.removeConsumer(authorConsumer);
|
||||
byte[] sig = authorSignature.sign();
|
||||
if(sig.length > Message.MAX_SIGNATURE_LENGTH)
|
||||
if(sig.length > ProtocolConstants.MAX_SIGNATURE_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
w.writeBytes(sig);
|
||||
}
|
||||
@@ -131,7 +138,7 @@ class MessageEncoderImpl implements MessageEncoder {
|
||||
} else {
|
||||
w.removeConsumer(groupConsumer);
|
||||
byte[] sig = groupSignature.sign();
|
||||
if(sig.length > Message.MAX_SIGNATURE_LENGTH)
|
||||
if(sig.length > ProtocolConstants.MAX_SIGNATURE_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
w.writeBytes(sig);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import net.sf.briar.api.protocol.AuthorId;
|
||||
import net.sf.briar.api.protocol.GroupId;
|
||||
import net.sf.briar.api.protocol.Message;
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
|
||||
/** A simple in-memory implementation of a message. */
|
||||
class MessageImpl implements Message {
|
||||
@@ -21,7 +22,7 @@ class MessageImpl implements Message {
|
||||
int bodyStart, int bodyLength) {
|
||||
if(bodyStart + bodyLength > raw.length)
|
||||
throw new IllegalArgumentException();
|
||||
if(bodyLength > Message.MAX_BODY_LENGTH)
|
||||
if(bodyLength > ProtocolConstants.MAX_BODY_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
|
||||
@@ -77,15 +77,15 @@ class MessageReader implements ObjectReader<Message> {
|
||||
r.removeObjectReader(Types.AUTHOR);
|
||||
}
|
||||
// Read the subject
|
||||
String subject = r.readString(Message.MAX_SUBJECT_LENGTH);
|
||||
String subject = r.readString(ProtocolConstants.MAX_SUBJECT_LENGTH);
|
||||
// Read the timestamp
|
||||
long timestamp = r.readInt64();
|
||||
if(timestamp < 0L) throw new FormatException();
|
||||
// Read the salt
|
||||
byte[] salt = r.readBytes(Message.SALT_LENGTH);
|
||||
if(salt.length != Message.SALT_LENGTH) throw new FormatException();
|
||||
byte[] salt = r.readBytes(ProtocolConstants.SALT_LENGTH);
|
||||
if(salt.length != ProtocolConstants.SALT_LENGTH) throw new FormatException();
|
||||
// Read the message body
|
||||
byte[] body = r.readBytes(Message.MAX_BODY_LENGTH);
|
||||
byte[] body = r.readBytes(ProtocolConstants.MAX_BODY_LENGTH);
|
||||
// Record the offset of the body within the message
|
||||
int bodyStart = (int) counting.getCount() - body.length;
|
||||
// Record the length of the data covered by the author's signature
|
||||
@@ -93,13 +93,13 @@ class MessageReader implements ObjectReader<Message> {
|
||||
// Read the author's signature, if there is one
|
||||
byte[] authorSig = null;
|
||||
if(author == null) r.readNull();
|
||||
else authorSig = r.readBytes(Message.MAX_SIGNATURE_LENGTH);
|
||||
else authorSig = r.readBytes(ProtocolConstants.MAX_SIGNATURE_LENGTH);
|
||||
// Record the length of the data covered by the group's signature
|
||||
int signedByGroup = (int) counting.getCount();
|
||||
// Read the group's signature, if there is one
|
||||
byte[] groupSig = null;
|
||||
if(group == null || group.getPublicKey() == null) r.readNull();
|
||||
else groupSig = r.readBytes(Message.MAX_SIGNATURE_LENGTH);
|
||||
else groupSig = r.readBytes(ProtocolConstants.MAX_SIGNATURE_LENGTH);
|
||||
// That's all, folks
|
||||
r.removeConsumer(counting);
|
||||
r.removeConsumer(copying);
|
||||
|
||||
@@ -9,13 +9,13 @@ import net.sf.briar.api.protocol.BatchId;
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.GroupFactory;
|
||||
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;
|
||||
import net.sf.briar.api.protocol.writers.MessageEncoder;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
@@ -33,8 +33,8 @@ public class ProtocolModule extends AbstractModule {
|
||||
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(SubscriptionUpdateFactory.class).to(SubscriptionUpdateFactoryImpl.class);
|
||||
bind(TransportUpdateFactory.class).to(TransportUpdateFactoryImpl.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -94,13 +94,13 @@ public class ProtocolModule extends AbstractModule {
|
||||
@Provides
|
||||
ObjectReader<SubscriptionUpdate> getSubscriptionReader(
|
||||
ObjectReader<Group> groupReader,
|
||||
SubscriptionFactory subscriptionFactory) {
|
||||
return new SubscriptionReader(groupReader, subscriptionFactory);
|
||||
SubscriptionUpdateFactory subscriptionFactory) {
|
||||
return new SubscriptionUpdateReader(groupReader, subscriptionFactory);
|
||||
}
|
||||
|
||||
@Provides
|
||||
ObjectReader<TransportUpdate> getTransportReader(
|
||||
TransportFactory transportFactory) {
|
||||
return new TransportReader(transportFactory);
|
||||
TransportUpdateFactory transportFactory) {
|
||||
return new TransportUpdateReader(transportFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.Map;
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.SubscriptionUpdate;
|
||||
|
||||
interface SubscriptionFactory {
|
||||
interface SubscriptionUpdateFactory {
|
||||
|
||||
SubscriptionUpdate createSubscriptions(Map<Group, Long> subs,
|
||||
long timestamp);
|
||||
@@ -5,7 +5,7 @@ import java.util.Map;
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.SubscriptionUpdate;
|
||||
|
||||
class SubscriptionFactoryImpl implements SubscriptionFactory {
|
||||
class SubscriptionUpdateFactoryImpl implements SubscriptionUpdateFactory {
|
||||
|
||||
public SubscriptionUpdate createSubscriptions(Map<Group, Long> subs,
|
||||
long timestamp) {
|
||||
@@ -12,13 +12,13 @@ import net.sf.briar.api.serial.Consumer;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
|
||||
class SubscriptionReader implements ObjectReader<SubscriptionUpdate> {
|
||||
class SubscriptionUpdateReader implements ObjectReader<SubscriptionUpdate> {
|
||||
|
||||
private final ObjectReader<Group> groupReader;
|
||||
private final SubscriptionFactory subscriptionFactory;
|
||||
private final SubscriptionUpdateFactory subscriptionFactory;
|
||||
|
||||
SubscriptionReader(ObjectReader<Group> groupReader,
|
||||
SubscriptionFactory subscriptionFactory) {
|
||||
SubscriptionUpdateReader(ObjectReader<Group> groupReader,
|
||||
SubscriptionUpdateFactory subscriptionFactory) {
|
||||
this.groupReader = groupReader;
|
||||
this.subscriptionFactory = subscriptionFactory;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
|
||||
interface TransportFactory {
|
||||
|
||||
TransportUpdate createTransportUpdate(
|
||||
Map<TransportId, TransportProperties> transports, long timestamp);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
|
||||
class TransportFactoryImpl implements TransportFactory {
|
||||
|
||||
public TransportUpdate createTransportUpdate(
|
||||
Map<TransportId, TransportProperties> transports, long timestamp) {
|
||||
return new TransportUpdateImpl(transports, timestamp);
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.briar.api.FormatException;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.serial.Consumer;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
|
||||
class TransportReader implements ObjectReader<TransportUpdate> {
|
||||
|
||||
private final TransportFactory transportFactory;
|
||||
private final ObjectReader<Transport> propertiesReader;
|
||||
|
||||
TransportReader(TransportFactory transportFactory) {
|
||||
this.transportFactory = transportFactory;
|
||||
propertiesReader = new PropertiesReader();
|
||||
}
|
||||
|
||||
public TransportUpdate readObject(Reader r) throws IOException {
|
||||
// Initialise the consumer
|
||||
Consumer counting =
|
||||
new CountingConsumer(ProtocolConstants.MAX_PACKET_LENGTH);
|
||||
// Read the data
|
||||
r.addConsumer(counting);
|
||||
r.readUserDefinedId(Types.TRANSPORT_UPDATE);
|
||||
r.addObjectReader(Types.TRANSPORT_PROPERTIES, propertiesReader);
|
||||
r.setMaxStringLength(ProtocolConstants.MAX_PACKET_LENGTH);
|
||||
List<Transport> l = r.readList(Transport.class);
|
||||
r.resetMaxStringLength();
|
||||
r.removeObjectReader(Types.TRANSPORT_PROPERTIES);
|
||||
if(l.size() > TransportUpdate.MAX_PLUGINS_PER_UPDATE)
|
||||
throw new FormatException();
|
||||
Map<TransportId, TransportProperties> transports =
|
||||
new HashMap<TransportId, TransportProperties>();
|
||||
for(Transport t : l) {
|
||||
if(transports.put(t.id, t.properties) != null)
|
||||
throw new FormatException(); // Duplicate transport ID
|
||||
}
|
||||
long timestamp = r.readInt64();
|
||||
r.removeConsumer(counting);
|
||||
// Build and return the transport update
|
||||
return transportFactory.createTransportUpdate(transports, timestamp);
|
||||
}
|
||||
|
||||
private static class Transport {
|
||||
|
||||
private final TransportId id;
|
||||
private final TransportProperties properties;
|
||||
|
||||
Transport(TransportId id, TransportProperties properties) {
|
||||
this.id = id;
|
||||
this.properties = properties;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PropertiesReader implements ObjectReader<Transport> {
|
||||
|
||||
public Transport readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedId(Types.TRANSPORT_PROPERTIES);
|
||||
int i = r.readInt32();
|
||||
if(i < TransportId.MIN_ID || i > TransportId.MAX_ID)
|
||||
throw new FormatException();
|
||||
TransportId id = new TransportId(i);
|
||||
r.setMaxStringLength(TransportUpdate.MAX_KEY_OR_VALUE_LENGTH);
|
||||
Map<String, String> m = r.readMap(String.class, String.class);
|
||||
r.resetMaxStringLength();
|
||||
if(m.size() > TransportUpdate.MAX_PROPERTIES_PER_PLUGIN)
|
||||
throw new FormatException();
|
||||
return new Transport(id, new TransportProperties(m));
|
||||
}
|
||||
}
|
||||
}
|
||||
12
components/net/sf/briar/protocol/TransportUpdateFactory.java
Normal file
12
components/net/sf/briar/protocol/TransportUpdateFactory.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import net.sf.briar.api.protocol.Transport;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
|
||||
interface TransportUpdateFactory {
|
||||
|
||||
TransportUpdate createTransportUpdate(Collection<Transport> transports,
|
||||
long timestamp);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import net.sf.briar.api.protocol.Transport;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
|
||||
class TransportUpdateFactoryImpl implements TransportUpdateFactory {
|
||||
|
||||
public TransportUpdate createTransportUpdate(
|
||||
Collection<Transport> transports, long timestamp) {
|
||||
return new TransportUpdateImpl(transports, timestamp);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,22 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.protocol.Transport;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
|
||||
class TransportUpdateImpl implements TransportUpdate {
|
||||
|
||||
private final Map<TransportId, TransportProperties> transports;
|
||||
private final Collection<Transport> transports;
|
||||
private final long timestamp;
|
||||
|
||||
TransportUpdateImpl(Map<TransportId, TransportProperties> transports,
|
||||
TransportUpdateImpl(Collection<Transport> transports,
|
||||
long timestamp) {
|
||||
this.transports = transports;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public Map<TransportId, TransportProperties> getTransports() {
|
||||
public Collection<Transport> getTransports() {
|
||||
return transports;
|
||||
}
|
||||
|
||||
|
||||
79
components/net/sf/briar/protocol/TransportUpdateReader.java
Normal file
79
components/net/sf/briar/protocol/TransportUpdateReader.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package net.sf.briar.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sf.briar.api.FormatException;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.Transport;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.UniqueId;
|
||||
import net.sf.briar.api.serial.Consumer;
|
||||
import net.sf.briar.api.serial.ObjectReader;
|
||||
import net.sf.briar.api.serial.Reader;
|
||||
|
||||
class TransportUpdateReader implements ObjectReader<TransportUpdate> {
|
||||
|
||||
private final TransportUpdateFactory transportUpdateFactory;
|
||||
private final ObjectReader<Transport> transportReader;
|
||||
|
||||
TransportUpdateReader(TransportUpdateFactory transportFactory) {
|
||||
this.transportUpdateFactory = transportFactory;
|
||||
transportReader = new TransportReader();
|
||||
}
|
||||
|
||||
public TransportUpdate readObject(Reader r) throws IOException {
|
||||
// Initialise the consumer
|
||||
Consumer counting =
|
||||
new CountingConsumer(ProtocolConstants.MAX_PACKET_LENGTH);
|
||||
// Read the data
|
||||
r.addConsumer(counting);
|
||||
r.readUserDefinedId(Types.TRANSPORT_UPDATE);
|
||||
r.addObjectReader(Types.TRANSPORT, transportReader);
|
||||
Collection<Transport> transports = r.readList(Transport.class);
|
||||
r.removeObjectReader(Types.TRANSPORT);
|
||||
if(transports.size() > ProtocolConstants.MAX_TRANSPORTS)
|
||||
throw new FormatException();
|
||||
long timestamp = r.readInt64();
|
||||
r.removeConsumer(counting);
|
||||
// Check for duplicate IDs or indices
|
||||
Set<TransportId> ids = new HashSet<TransportId>();
|
||||
Set<TransportIndex> indices = new HashSet<TransportIndex>();
|
||||
for(Transport t : transports) {
|
||||
if(!ids.add(t.getId())) throw new FormatException();
|
||||
if(!indices.add(t.getIndex())) throw new FormatException();
|
||||
}
|
||||
// Build and return the transport update
|
||||
return transportUpdateFactory.createTransportUpdate(transports,
|
||||
timestamp);
|
||||
}
|
||||
|
||||
private class TransportReader implements ObjectReader<Transport> {
|
||||
|
||||
public Transport readObject(Reader r) throws IOException {
|
||||
r.readUserDefinedId(Types.TRANSPORT);
|
||||
// Read the ID
|
||||
byte[] b = r.readBytes(UniqueId.LENGTH);
|
||||
if(b.length != UniqueId.LENGTH) throw new FormatException();
|
||||
TransportId id = new TransportId(b);
|
||||
// Read the index
|
||||
int i = r.readInt32();
|
||||
if(i < 0 || i >= ProtocolConstants.MAX_TRANSPORTS)
|
||||
throw new FormatException();
|
||||
TransportIndex index = new TransportIndex(i);
|
||||
// Read the properties
|
||||
r.setMaxStringLength(ProtocolConstants.MAX_PROPERTY_LENGTH);
|
||||
Map<String, String> m = r.readMap(String.class, String.class);
|
||||
r.resetMaxStringLength();
|
||||
if(m.size() > ProtocolConstants.MAX_PROPERTIES_PER_TRANSPORT)
|
||||
throw new FormatException();
|
||||
return new Transport(id, index, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,8 @@ class AckWriterImpl implements AckWriter {
|
||||
int overhead = started ? footerLength : headerLength + footerLength;
|
||||
if(capacity < idLength + overhead) return false;
|
||||
if(!started) start();
|
||||
b.writeTo(w);
|
||||
w.writeUserDefinedId(Types.BATCH_ID);
|
||||
w.writeBytes(b.getBytes());
|
||||
capacity -= idLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.sf.briar.protocol.writers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.protocol.Author;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.writers.AuthorWriter;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
class AuthorWriterImpl implements AuthorWriter {
|
||||
|
||||
public void writeAuthor(Writer w, Author a) throws IOException {
|
||||
w.writeUserDefinedId(Types.AUTHOR);
|
||||
w.writeString(a.getName());
|
||||
w.writeBytes(a.getPublicKey());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.sf.briar.protocol.writers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.writers.GroupWriter;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
class GroupWriterImpl implements GroupWriter {
|
||||
|
||||
public void writeGroup(Writer w, Group g) throws IOException {
|
||||
w.writeUserDefinedId(Types.GROUP);
|
||||
w.writeString(g.getName());
|
||||
byte[] publicKey = g.getPublicKey();
|
||||
if(publicKey == null) w.writeNull();
|
||||
else w.writeBytes(publicKey);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,8 @@ class OfferWriterImpl implements OfferWriter {
|
||||
int overhead = started ? footerLength : headerLength + footerLength;
|
||||
if(capacity < idLength + overhead) return false;
|
||||
if(!started) start();
|
||||
m.writeTo(w);
|
||||
w.writeUserDefinedId(Types.MESSAGE_ID);
|
||||
w.writeBytes(m.getBytes());
|
||||
capacity -= idLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.sf.briar.protocol.writers;
|
||||
|
||||
import net.sf.briar.api.protocol.writers.AuthorWriter;
|
||||
import net.sf.briar.api.protocol.writers.GroupWriter;
|
||||
import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
@@ -8,6 +10,8 @@ public class ProtocolWritersModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(AuthorWriter.class).to(AuthorWriterImpl.class);
|
||||
bind(GroupWriter.class).to(GroupWriterImpl.class);
|
||||
bind(ProtocolWriterFactory.class).to(ProtocolWriterFactoryImpl.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ package net.sf.briar.protocol.writers;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.writers.GroupWriter;
|
||||
import net.sf.briar.api.protocol.writers.SubscriptionWriter;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
@@ -14,16 +16,23 @@ class SubscriptionWriterImpl implements SubscriptionWriter {
|
||||
|
||||
private final OutputStream out;
|
||||
private final Writer w;
|
||||
private final GroupWriter groupWriter;
|
||||
|
||||
SubscriptionWriterImpl(OutputStream out, WriterFactory writerFactory) {
|
||||
this.out = out;
|
||||
w = writerFactory.createWriter(out);
|
||||
groupWriter = new GroupWriterImpl();
|
||||
}
|
||||
|
||||
public void writeSubscriptions(Map<Group, Long> subs, long timestamp)
|
||||
throws IOException {
|
||||
w.writeUserDefinedId(Types.SUBSCRIPTION_UPDATE);
|
||||
w.writeMap(subs);
|
||||
w.writeMapStart();
|
||||
for(Entry<Group, Long> e : subs.entrySet()) {
|
||||
groupWriter.writeGroup(w, e.getKey());
|
||||
w.writeInt64(e.getValue());
|
||||
}
|
||||
w.writeMapEnd();
|
||||
w.writeInt64(timestamp);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ package net.sf.briar.protocol.writers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Collection;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.protocol.Transport;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.writers.TransportWriter;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
@@ -22,15 +20,15 @@ class TransportWriterImpl implements TransportWriter {
|
||||
w = writerFactory.createWriter(out);
|
||||
}
|
||||
|
||||
public void writeTransports(
|
||||
Map<TransportId, TransportProperties> transports, long timestamp)
|
||||
throws IOException {
|
||||
public void writeTransports(Collection<Transport> transports,
|
||||
long timestamp) throws IOException {
|
||||
w.writeUserDefinedId(Types.TRANSPORT_UPDATE);
|
||||
w.writeListStart();
|
||||
for(Entry<TransportId, TransportProperties> e : transports.entrySet()) {
|
||||
w.writeUserDefinedId(Types.TRANSPORT_PROPERTIES);
|
||||
w.writeInt32(e.getKey().getInt());
|
||||
w.writeMap(e.getValue());
|
||||
for(Transport p : transports) {
|
||||
w.writeUserDefinedId(Types.TRANSPORT);
|
||||
w.writeBytes(p.getId().getBytes());
|
||||
w.writeInt32(p.getIndex().getInt());
|
||||
w.writeMap(p);
|
||||
}
|
||||
w.writeListEnd();
|
||||
w.writeInt64(timestamp);
|
||||
|
||||
@@ -10,7 +10,6 @@ import java.util.Map.Entry;
|
||||
|
||||
import net.sf.briar.api.Bytes;
|
||||
import net.sf.briar.api.serial.Consumer;
|
||||
import net.sf.briar.api.serial.Writable;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
class WriterImpl implements Writer {
|
||||
@@ -139,8 +138,7 @@ class WriterImpl implements Writer {
|
||||
}
|
||||
|
||||
private void writeObject(Object o) throws IOException {
|
||||
if(o instanceof Writable) ((Writable) o).writeTo(this);
|
||||
else if(o instanceof Boolean) writeBoolean((Boolean) o);
|
||||
if(o instanceof Boolean) writeBoolean((Boolean) o);
|
||||
else if(o instanceof Byte) writeIntAny((Byte) o);
|
||||
else if(o instanceof Short) writeIntAny((Short) o);
|
||||
else if(o instanceof Integer) writeIntAny((Integer) o);
|
||||
|
||||
38
components/net/sf/briar/transport/ConnectionContextImpl.java
Normal file
38
components/net/sf/briar/transport/ConnectionContextImpl.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.transport.ConnectionContext;
|
||||
|
||||
class ConnectionContextImpl implements ConnectionContext {
|
||||
|
||||
private final ContactId contactId;
|
||||
private final TransportId transportId;
|
||||
private final TransportIndex transportIndex;
|
||||
private final long connectionNumber;
|
||||
|
||||
ConnectionContextImpl(ContactId contactId, TransportId transportId,
|
||||
TransportIndex transportIndex, long connectionNumber) {
|
||||
this.contactId = contactId;
|
||||
this.transportId = transportId;
|
||||
this.transportIndex = transportIndex;
|
||||
this.connectionNumber = connectionNumber;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public TransportId getTransportId() {
|
||||
return transportId;
|
||||
}
|
||||
|
||||
public TransportIndex getTransportIndex() {
|
||||
return transportIndex;
|
||||
}
|
||||
|
||||
public long getConnectionNumber() {
|
||||
return connectionNumber;
|
||||
}
|
||||
}
|
||||
@@ -2,41 +2,41 @@ package net.sf.briar.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.transport.BatchConnectionFactory;
|
||||
import net.sf.briar.api.transport.BatchTransportReader;
|
||||
import net.sf.briar.api.transport.BatchTransportWriter;
|
||||
import net.sf.briar.api.transport.ConnectionContext;
|
||||
import net.sf.briar.api.transport.ConnectionDispatcher;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniser;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniserFactory;
|
||||
import net.sf.briar.api.transport.StreamConnectionFactory;
|
||||
import net.sf.briar.api.transport.StreamTransportConnection;
|
||||
import net.sf.briar.api.transport.TransportConstants;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ConnectionDispatcherImpl.class.getName());
|
||||
|
||||
private final ConnectionRecogniserFactory recFactory;
|
||||
private final ConnectionRecogniser recogniser;
|
||||
private final BatchConnectionFactory batchConnFactory;
|
||||
private final StreamConnectionFactory streamConnFactory;
|
||||
private final Map<TransportId, ConnectionRecogniser> recognisers;
|
||||
|
||||
ConnectionDispatcherImpl(ConnectionRecogniserFactory recFactory,
|
||||
@Inject
|
||||
ConnectionDispatcherImpl(ConnectionRecogniser recogniser,
|
||||
BatchConnectionFactory batchConnFactory,
|
||||
StreamConnectionFactory streamConnFactory) {
|
||||
this.recFactory = recFactory;
|
||||
this.recogniser = recogniser;
|
||||
this.batchConnFactory = batchConnFactory;
|
||||
this.streamConnFactory = streamConnFactory;
|
||||
recognisers = new HashMap<TransportId, ConnectionRecogniser>();
|
||||
}
|
||||
|
||||
public void dispatchReader(TransportId t, BatchTransportReader r) {
|
||||
@@ -49,21 +49,27 @@ public class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
||||
r.dispose(false);
|
||||
return;
|
||||
}
|
||||
// Get the contact ID, or null if the IV wasn't expected
|
||||
ContactId c;
|
||||
// Get the connection context, or null if the IV wasn't expected
|
||||
ConnectionContext ctx;
|
||||
try {
|
||||
ConnectionRecogniser rec = getRecogniser(t);
|
||||
c = rec.acceptConnection(encryptedIv);
|
||||
ctx = recogniser.acceptConnection(encryptedIv);
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||
r.dispose(false);
|
||||
return;
|
||||
}
|
||||
if(c == null) {
|
||||
if(ctx == null) {
|
||||
r.dispose(false);
|
||||
return;
|
||||
}
|
||||
batchConnFactory.createIncomingConnection(t, c, r, encryptedIv);
|
||||
if(!t.equals(ctx.getTransportId())) {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning("Connection has unexpected transport ID");
|
||||
r.dispose(false);
|
||||
return;
|
||||
}
|
||||
batchConnFactory.createIncomingConnection(ctx.getTransportIndex(),
|
||||
ctx.getContactId(), r, encryptedIv);
|
||||
}
|
||||
|
||||
private byte[] readIv(InputStream in) throws IOException {
|
||||
@@ -77,20 +83,9 @@ public class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
||||
return b;
|
||||
}
|
||||
|
||||
private ConnectionRecogniser getRecogniser(TransportId t) {
|
||||
synchronized(recognisers) {
|
||||
ConnectionRecogniser rec = recognisers.get(t);
|
||||
if(rec == null) {
|
||||
rec = recFactory.createConnectionRecogniser(t);
|
||||
recognisers.put(t, rec);
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchWriter(TransportId t, ContactId c,
|
||||
public void dispatchWriter(TransportIndex i, ContactId c,
|
||||
BatchTransportWriter w) {
|
||||
batchConnFactory.createOutgoingConnection(t, c, w);
|
||||
batchConnFactory.createOutgoingConnection(i, c, w);
|
||||
}
|
||||
|
||||
public void dispatchIncomingConnection(TransportId t,
|
||||
@@ -104,25 +99,31 @@ public class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
||||
s.dispose(false);
|
||||
return;
|
||||
}
|
||||
// Get the contact ID, or null if the IV wasn't expected
|
||||
ContactId c;
|
||||
// Get the connection context, or null if the IV wasn't expected
|
||||
ConnectionContext ctx;
|
||||
try {
|
||||
ConnectionRecogniser rec = getRecogniser(t);
|
||||
c = rec.acceptConnection(encryptedIv);
|
||||
ctx = recogniser.acceptConnection(encryptedIv);
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||
s.dispose(false);
|
||||
return;
|
||||
}
|
||||
if(c == null) {
|
||||
if(ctx == null) {
|
||||
s.dispose(false);
|
||||
return;
|
||||
}
|
||||
streamConnFactory.createIncomingConnection(t, c, s, encryptedIv);
|
||||
if(!t.equals(ctx.getTransportId())) {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning("Connection has unexpected transport ID");
|
||||
s.dispose(false);
|
||||
return;
|
||||
}
|
||||
streamConnFactory.createIncomingConnection(ctx.getTransportIndex(),
|
||||
ctx.getContactId(), s, encryptedIv);
|
||||
}
|
||||
|
||||
public void dispatchOutgoingConnection(TransportId t, ContactId c,
|
||||
public void dispatchOutgoingConnection(TransportIndex i, ContactId c,
|
||||
StreamTransportConnection s) {
|
||||
streamConnFactory.createOutgoingConnection(t, c, s);
|
||||
streamConnFactory.createOutgoingConnection(i, c, s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.transport.ConnectionReader;
|
||||
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
||||
|
||||
@@ -26,7 +26,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
||||
}
|
||||
|
||||
public ConnectionReader createConnectionReader(InputStream in,
|
||||
TransportId t, byte[] encryptedIv, byte[] secret) {
|
||||
TransportIndex i, byte[] encryptedIv, byte[] secret) {
|
||||
// Decrypt the IV
|
||||
Cipher ivCipher = crypto.getIvCipher();
|
||||
SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
|
||||
@@ -42,21 +42,22 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
||||
throw new IllegalArgumentException(badKey);
|
||||
}
|
||||
// Validate the IV
|
||||
if(!IvEncoder.validateIv(iv, true, t))
|
||||
if(!IvEncoder.validateIv(iv, true, i))
|
||||
throw new IllegalArgumentException();
|
||||
// Copy the connection number
|
||||
long connection = IvEncoder.getConnectionNumber(iv);
|
||||
return createConnectionReader(in, true, t, connection, secret);
|
||||
return createConnectionReader(in, true, i, connection, secret);
|
||||
}
|
||||
|
||||
public ConnectionReader createConnectionReader(InputStream in,
|
||||
TransportId t, long connection, byte[] secret) {
|
||||
return createConnectionReader(in, false, t, connection, secret);
|
||||
TransportIndex i, long connection, byte[] secret) {
|
||||
return createConnectionReader(in, false, i, connection, secret);
|
||||
}
|
||||
|
||||
private ConnectionReader createConnectionReader(InputStream in,
|
||||
boolean initiator, TransportId t, long connection, byte[] secret) {
|
||||
byte[] iv = IvEncoder.encodeIv(initiator, t, connection);
|
||||
boolean initiator, TransportIndex i, long connection,
|
||||
byte[] secret) {
|
||||
byte[] iv = IvEncoder.encodeIv(initiator, i, connection);
|
||||
// Create the decrypter
|
||||
Cipher frameCipher = crypto.getFrameCipher();
|
||||
SecretKey frameKey = crypto.deriveIncomingFrameKey(secret);
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniser;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniserFactory;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
class ConnectionRecogniserFactoryImpl implements ConnectionRecogniserFactory {
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final DatabaseComponent db;
|
||||
|
||||
@Inject
|
||||
ConnectionRecogniserFactoryImpl(CryptoComponent crypto,
|
||||
DatabaseComponent db) {
|
||||
this.crypto = crypto;
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public ConnectionRecogniser createConnectionRecogniser(TransportId t) {
|
||||
return new ConnectionRecogniserImpl(t, crypto, db);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,13 @@ package net.sf.briar.transport;
|
||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
@@ -13,128 +18,178 @@ import javax.crypto.SecretKey;
|
||||
|
||||
import net.sf.briar.api.Bytes;
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.NoSuchContactException;
|
||||
import net.sf.briar.api.db.event.ContactAddedEvent;
|
||||
import net.sf.briar.api.db.event.ContactRemovedEvent;
|
||||
import net.sf.briar.api.db.event.DatabaseEvent;
|
||||
import net.sf.briar.api.db.event.DatabaseListener;
|
||||
import net.sf.briar.api.db.event.TransportAddedEvent;
|
||||
import net.sf.briar.api.db.event.RemoteTransportsUpdatedEvent;
|
||||
import net.sf.briar.api.protocol.Transport;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.transport.ConnectionContext;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniser;
|
||||
import net.sf.briar.api.transport.ConnectionWindow;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
class ConnectionRecogniserImpl implements ConnectionRecogniser,
|
||||
DatabaseListener {
|
||||
|
||||
private final TransportId id;
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ConnectionRecogniserImpl.class.getName());
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final DatabaseComponent db;
|
||||
private final Map<Bytes, ContactId> ivToContact;
|
||||
private final Map<Bytes, Long> ivToConnectionNumber;
|
||||
private final Map<ContactId, Map<Long, Bytes>> contactToIvs;
|
||||
private final Map<ContactId, Cipher> contactToCipher;
|
||||
private final Map<ContactId, ConnectionWindow> contactToWindow;
|
||||
private final Cipher ivCipher;
|
||||
private final Map<Bytes, ConnectionContext> expected;
|
||||
private final Collection<TransportId> localTransportIds;
|
||||
|
||||
private boolean initialised = false;
|
||||
|
||||
ConnectionRecogniserImpl(TransportId id, CryptoComponent crypto,
|
||||
DatabaseComponent db) {
|
||||
this.id = id;
|
||||
@Inject
|
||||
ConnectionRecogniserImpl(CryptoComponent crypto, DatabaseComponent db) {
|
||||
this.crypto = crypto;
|
||||
this.db = db;
|
||||
// FIXME: There's probably a tidier way of maintaining all this state
|
||||
ivToContact = new HashMap<Bytes, ContactId>();
|
||||
ivToConnectionNumber = new HashMap<Bytes, Long>();
|
||||
contactToIvs = new HashMap<ContactId, Map<Long, Bytes>>();
|
||||
contactToCipher = new HashMap<ContactId, Cipher>();
|
||||
contactToWindow = new HashMap<ContactId, ConnectionWindow>();
|
||||
ivCipher = crypto.getIvCipher();
|
||||
expected = new HashMap<Bytes, ConnectionContext>();
|
||||
localTransportIds = new ArrayList<TransportId>();
|
||||
db.addListener(this);
|
||||
}
|
||||
|
||||
private synchronized void initialise() throws DbException {
|
||||
for(Transport t : db.getLocalTransports()) {
|
||||
localTransportIds.add(t.getId());
|
||||
}
|
||||
for(ContactId c : db.getContacts()) {
|
||||
try {
|
||||
// Initialise and store the contact's IV cipher
|
||||
byte[] secret = db.getSharedSecret(c);
|
||||
SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
|
||||
Cipher cipher = crypto.getIvCipher();
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||
} catch(InvalidKeyException badKey) {
|
||||
throw new RuntimeException(badKey);
|
||||
}
|
||||
contactToCipher.put(c, cipher);
|
||||
// Calculate the IVs for the contact's connection window
|
||||
ConnectionWindow w = db.getConnectionWindow(c, id);
|
||||
Map<Long, Bytes> ivs = new HashMap<Long, Bytes>();
|
||||
for(Long unseen : w.getUnseenConnectionNumbers()) {
|
||||
Bytes expectedIv = new Bytes(encryptIv(c, unseen));
|
||||
ivToContact.put(expectedIv, c);
|
||||
ivToConnectionNumber.put(expectedIv, unseen);
|
||||
ivs.put(unseen, expectedIv);
|
||||
}
|
||||
contactToIvs.put(c, ivs);
|
||||
contactToWindow.put(c, w);
|
||||
calculateIvs(c);
|
||||
} catch(NoSuchContactException e) {
|
||||
// The contact was removed after the call to getContacts()
|
||||
continue;
|
||||
// The contact was removed - clean up in eventOccurred()
|
||||
}
|
||||
}
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
private synchronized byte[] encryptIv(ContactId c, long connection) {
|
||||
byte[] iv = IvEncoder.encodeIv(true, id, connection);
|
||||
Cipher cipher = contactToCipher.get(c);
|
||||
assert cipher != null;
|
||||
private synchronized void calculateIvs(ContactId c) throws DbException {
|
||||
SecretKey ivKey = crypto.deriveIncomingIvKey(db.getSharedSecret(c));
|
||||
for(TransportId t : localTransportIds) {
|
||||
TransportIndex i = db.getRemoteIndex(c, t);
|
||||
if(i != null) {
|
||||
ConnectionWindow w = db.getConnectionWindow(c, i);
|
||||
calculateIvs(c, t, i, ivKey, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void calculateIvs(ContactId c, TransportId t,
|
||||
TransportIndex i, SecretKey ivKey, ConnectionWindow w)
|
||||
throws DbException {
|
||||
for(Long unseen : w.getUnseenConnectionNumbers()) {
|
||||
Bytes iv = new Bytes(encryptIv(i, unseen, ivKey));
|
||||
expected.put(iv, new ConnectionContextImpl(c, t, i, unseen));
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized byte[] encryptIv(TransportIndex i, long connection,
|
||||
SecretKey ivKey) {
|
||||
byte[] iv = IvEncoder.encodeIv(true, i, connection);
|
||||
try {
|
||||
return cipher.doFinal(iv);
|
||||
ivCipher.init(Cipher.ENCRYPT_MODE, ivKey);
|
||||
return ivCipher.doFinal(iv);
|
||||
} catch(BadPaddingException badCipher) {
|
||||
throw new RuntimeException(badCipher);
|
||||
} catch(IllegalBlockSizeException badCipher) {
|
||||
throw new RuntimeException(badCipher);
|
||||
} catch(InvalidKeyException badKey) {
|
||||
throw new RuntimeException(badKey);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ContactId acceptConnection(byte[] encryptedIv)
|
||||
public synchronized ConnectionContext acceptConnection(byte[] encryptedIv)
|
||||
throws DbException {
|
||||
if(encryptedIv.length != IV_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
if(!initialised) initialise();
|
||||
Bytes b = new Bytes(encryptedIv);
|
||||
ContactId contactId = ivToContact.remove(b);
|
||||
Long connection = ivToConnectionNumber.remove(b);
|
||||
assert (contactId == null) == (connection == null);
|
||||
if(contactId == null) return null;
|
||||
// The IV was expected - update and save the connection window
|
||||
ConnectionWindow w = contactToWindow.get(contactId);
|
||||
assert w != null;
|
||||
w.setSeen(connection);
|
||||
db.setConnectionWindow(contactId, id, w);
|
||||
// Update the set of expected IVs
|
||||
Map<Long, Bytes> oldIvs = contactToIvs.remove(contactId);
|
||||
assert oldIvs != null;
|
||||
assert oldIvs.containsKey(connection);
|
||||
Map<Long, Bytes> newIvs = new HashMap<Long, Bytes>();
|
||||
for(Long unseen : w.getUnseenConnectionNumbers()) {
|
||||
Bytes expectedIv = oldIvs.get(unseen);
|
||||
if(expectedIv == null) {
|
||||
expectedIv = new Bytes(encryptIv(contactId, unseen));
|
||||
ivToContact.put(expectedIv, contactId);
|
||||
ivToConnectionNumber.put(expectedIv, connection);
|
||||
ConnectionContext ctx = expected.remove(new Bytes(encryptedIv));
|
||||
if(ctx == null) return null; // The IV was not expected
|
||||
try {
|
||||
ContactId c = ctx.getContactId();
|
||||
TransportIndex i = ctx.getTransportIndex();
|
||||
// Update the connection window
|
||||
ConnectionWindow w = db.getConnectionWindow(c, i);
|
||||
w.setSeen(ctx.getConnectionNumber());
|
||||
db.setConnectionWindow(c, i, w);
|
||||
// Update the set of expected IVs
|
||||
Iterator<ConnectionContext> it = expected.values().iterator();
|
||||
while(it.hasNext()) {
|
||||
ConnectionContext ctx1 = it.next();
|
||||
ContactId c1 = ctx1.getContactId();
|
||||
TransportIndex i1 = ctx1.getTransportIndex();
|
||||
if(c1.equals(c) && i1.equals(i)) it.remove();
|
||||
}
|
||||
newIvs.put(unseen, expectedIv);
|
||||
SecretKey ivKey = crypto.deriveIncomingIvKey(db.getSharedSecret(c));
|
||||
calculateIvs(c, ctx.getTransportId(), i, ivKey, w);
|
||||
} catch(NoSuchContactException e) {
|
||||
// The contact was removed - clean up when we get the event
|
||||
}
|
||||
contactToIvs.put(contactId, newIvs);
|
||||
return contactId;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
public void eventOccurred(DatabaseEvent e) {
|
||||
// When the set of contacts changes we need to re-initialise everything
|
||||
if(e instanceof ContactAddedEvent || e instanceof ContactRemovedEvent) {
|
||||
if(e instanceof ContactRemovedEvent) {
|
||||
// Remove the expected IVs for the ex-contact
|
||||
removeIvs(((ContactRemovedEvent) e).getContactId());
|
||||
} else if(e instanceof TransportAddedEvent) {
|
||||
// Calculate the expected IVs for the new transport
|
||||
TransportId t = ((TransportAddedEvent) e).getTransportId();
|
||||
synchronized(this) {
|
||||
initialised = false;
|
||||
if(!initialised) return;
|
||||
try {
|
||||
localTransportIds.add(t);
|
||||
calculateIvs(t);
|
||||
} catch(DbException e1) {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning(e1.getMessage());
|
||||
}
|
||||
}
|
||||
} else if(e instanceof RemoteTransportsUpdatedEvent) {
|
||||
// Remove and recalculate the expected IVs for the contact
|
||||
ContactId c = ((RemoteTransportsUpdatedEvent) e).getContactId();
|
||||
synchronized(this) {
|
||||
if(!initialised) return;
|
||||
removeIvs(c);
|
||||
try {
|
||||
calculateIvs(c);
|
||||
} catch(DbException e1) {
|
||||
if(LOG.isLoggable(Level.WARNING))
|
||||
LOG.warning(e1.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void removeIvs(ContactId c) {
|
||||
if(!initialised) return;
|
||||
Iterator<ConnectionContext> it = expected.values().iterator();
|
||||
while(it.hasNext()) if(it.next().getContactId().equals(c)) it.remove();
|
||||
}
|
||||
|
||||
private synchronized void calculateIvs(TransportId t) throws DbException {
|
||||
for(ContactId c : db.getContacts()) {
|
||||
try {
|
||||
byte[] secret = db.getSharedSecret(c);
|
||||
SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
|
||||
TransportIndex i = db.getRemoteIndex(c, t);
|
||||
if(i != null) {
|
||||
ConnectionWindow w = db.getConnectionWindow(c, i);
|
||||
calculateIvs(c, t, i, ivKey, w);
|
||||
}
|
||||
} catch(NoSuchContactException e) {
|
||||
// The contact was removed - clean up when we get the event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.transport.ConnectionWriter;
|
||||
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
||||
|
||||
@@ -26,13 +26,14 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
||||
}
|
||||
|
||||
public ConnectionWriter createConnectionWriter(OutputStream out,
|
||||
long capacity, TransportId t, long connection, byte[] secret) {
|
||||
return createConnectionWriter(out, capacity, true, t, connection,
|
||||
long capacity, TransportIndex i, long connection, byte[] secret) {
|
||||
return createConnectionWriter(out, capacity, true, i, connection,
|
||||
secret);
|
||||
}
|
||||
|
||||
public ConnectionWriter createConnectionWriter(OutputStream out,
|
||||
long capacity, TransportId t, byte[] encryptedIv, byte[] secret) {
|
||||
long capacity, TransportIndex i, byte[] encryptedIv,
|
||||
byte[] secret) {
|
||||
// Decrypt the IV
|
||||
Cipher ivCipher = crypto.getIvCipher();
|
||||
SecretKey ivKey = crypto.deriveIncomingIvKey(secret);
|
||||
@@ -48,23 +49,23 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
||||
throw new RuntimeException(badKey);
|
||||
}
|
||||
// Validate the IV
|
||||
if(!IvEncoder.validateIv(iv, true, t))
|
||||
if(!IvEncoder.validateIv(iv, true, i))
|
||||
throw new IllegalArgumentException();
|
||||
// Copy the connection number
|
||||
long connection = IvEncoder.getConnectionNumber(iv);
|
||||
return createConnectionWriter(out, capacity, false, t, connection,
|
||||
return createConnectionWriter(out, capacity, false, i, connection,
|
||||
secret);
|
||||
}
|
||||
|
||||
private ConnectionWriter createConnectionWriter(OutputStream out,
|
||||
long capacity, boolean initiator, TransportId t, long connection,
|
||||
long capacity, boolean initiator, TransportIndex i, long connection,
|
||||
byte[] secret) {
|
||||
// Create the encrypter
|
||||
Cipher ivCipher = crypto.getIvCipher();
|
||||
Cipher frameCipher = crypto.getFrameCipher();
|
||||
SecretKey ivKey = crypto.deriveOutgoingIvKey(secret);
|
||||
SecretKey frameKey = crypto.deriveOutgoingFrameKey(secret);
|
||||
byte[] iv = IvEncoder.encodeIv(initiator, t, connection);
|
||||
byte[] iv = IvEncoder.encodeIv(initiator, i, connection);
|
||||
ConnectionEncrypter encrypter = new ConnectionEncrypterImpl(out,
|
||||
capacity, iv, ivCipher, frameCipher, ivKey, frameKey);
|
||||
// Create the writer
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.util.ByteUtils;
|
||||
|
||||
class IvEncoder {
|
||||
|
||||
static byte[] encodeIv(boolean initiator, TransportId transport,
|
||||
static byte[] encodeIv(boolean initiator, TransportIndex i,
|
||||
long connection) {
|
||||
byte[] iv = new byte[IV_LENGTH];
|
||||
// Bit 31 is the initiator flag
|
||||
if(initiator) iv[3] = 1;
|
||||
// Encode the transport identifier as an unsigned 16-bit integer
|
||||
ByteUtils.writeUint16(transport.getInt(), iv, 4);
|
||||
ByteUtils.writeUint16(i.getInt(), iv, 4);
|
||||
// Encode the connection number as an unsigned 32-bit integer
|
||||
ByteUtils.writeUint32(connection, iv, 6);
|
||||
return iv;
|
||||
@@ -24,16 +24,16 @@ class IvEncoder {
|
||||
ByteUtils.writeUint32(frame, iv, 10);
|
||||
}
|
||||
|
||||
static boolean validateIv(byte[] iv, boolean initiator, TransportId t) {
|
||||
static boolean validateIv(byte[] iv, boolean initiator, TransportIndex i) {
|
||||
if(iv.length != IV_LENGTH) return false;
|
||||
// Check that the reserved bits are all zero
|
||||
for(int i = 0; i < 2; i++) if(iv[i] != 0) return false;
|
||||
for(int j = 0; j < 2; j++) if(iv[j] != 0) return false;
|
||||
if(iv[3] != 0 && iv[3] != 1) return false;
|
||||
for(int i = 10; i < iv.length; i++) if(iv[i] != 0) return false;
|
||||
for(int j = 10; j < iv.length; j++) if(iv[j] != 0) return false;
|
||||
// Check that the initiator flag matches
|
||||
if(initiator != getInitiatorFlag(iv)) return false;
|
||||
// Check that the transport ID matches
|
||||
if(t.getInt() != getTransportId(iv)) return false;
|
||||
if(i.getInt() != getTransportId(iv)) return false;
|
||||
// The IV is valid
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
|
||||
import net.sf.briar.api.serial.Consumer;
|
||||
|
||||
/** A consumer that passes its input through a MAC. */
|
||||
class MacConsumer implements Consumer {
|
||||
|
||||
private final Mac mac;
|
||||
|
||||
MacConsumer(Mac mac) {
|
||||
this.mac = mac;
|
||||
}
|
||||
|
||||
public void write(byte b) {
|
||||
mac.update(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) {
|
||||
mac.update(b, off, len);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import net.sf.briar.api.transport.ConnectionDispatcher;
|
||||
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniserFactory;
|
||||
import net.sf.briar.api.transport.ConnectionRecogniser;
|
||||
import net.sf.briar.api.transport.ConnectionWindowFactory;
|
||||
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
||||
|
||||
@@ -11,10 +12,10 @@ public class TransportModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(ConnectionDispatcher.class).to(ConnectionDispatcherImpl.class);
|
||||
bind(ConnectionReaderFactory.class).to(
|
||||
ConnectionReaderFactoryImpl.class);
|
||||
bind(ConnectionRecogniserFactory.class).to(
|
||||
ConnectionRecogniserFactoryImpl.class);
|
||||
bind(ConnectionRecogniser.class).to(ConnectionRecogniserImpl.class);
|
||||
bind(ConnectionWindowFactory.class).to(
|
||||
ConnectionWindowFactoryImpl.class);
|
||||
bind(ConnectionWriterFactory.class).to(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package net.sf.briar.transport.batch;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.protocol.ProtocolReaderFactory;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
|
||||
import net.sf.briar.api.transport.BatchConnectionFactory;
|
||||
import net.sf.briar.api.transport.BatchTransportReader;
|
||||
@@ -33,10 +33,10 @@ class BatchConnectionFactoryImpl implements BatchConnectionFactory {
|
||||
this.protoWriterFactory = protoWriterFactory;
|
||||
}
|
||||
|
||||
public void createIncomingConnection(TransportId t, ContactId c,
|
||||
public void createIncomingConnection(TransportIndex i, ContactId c,
|
||||
BatchTransportReader r, byte[] encryptedIv) {
|
||||
final IncomingBatchConnection conn = new IncomingBatchConnection(
|
||||
connReaderFactory, db, protoReaderFactory, t, c, r,
|
||||
connReaderFactory, db, protoReaderFactory, i, c, r,
|
||||
encryptedIv);
|
||||
Runnable read = new Runnable() {
|
||||
public void run() {
|
||||
@@ -46,10 +46,10 @@ class BatchConnectionFactoryImpl implements BatchConnectionFactory {
|
||||
new Thread(read).start();
|
||||
}
|
||||
|
||||
public void createOutgoingConnection(TransportId t, ContactId c,
|
||||
public void createOutgoingConnection(TransportIndex i, ContactId c,
|
||||
BatchTransportWriter w) {
|
||||
final OutgoingBatchConnection conn = new OutgoingBatchConnection(
|
||||
connWriterFactory, db, protoWriterFactory, t, c, w);
|
||||
connWriterFactory, db, protoWriterFactory, i, c, w);
|
||||
Runnable write = new Runnable() {
|
||||
public void run() {
|
||||
conn.write();
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.FormatException;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
@@ -14,6 +13,7 @@ import net.sf.briar.api.protocol.Batch;
|
||||
import net.sf.briar.api.protocol.ProtocolReader;
|
||||
import net.sf.briar.api.protocol.ProtocolReaderFactory;
|
||||
import net.sf.briar.api.protocol.SubscriptionUpdate;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.transport.BatchTransportReader;
|
||||
import net.sf.briar.api.transport.ConnectionReader;
|
||||
@@ -27,19 +27,19 @@ class IncomingBatchConnection {
|
||||
private final ConnectionReaderFactory connFactory;
|
||||
private final DatabaseComponent db;
|
||||
private final ProtocolReaderFactory protoFactory;
|
||||
private final TransportId transportId;
|
||||
private final TransportIndex transportIndex;
|
||||
private final ContactId contactId;
|
||||
private final BatchTransportReader reader;
|
||||
private final byte[] encryptedIv;
|
||||
|
||||
IncomingBatchConnection(ConnectionReaderFactory connFactory,
|
||||
DatabaseComponent db, ProtocolReaderFactory protoFactory,
|
||||
TransportId transportId, ContactId contactId,
|
||||
TransportIndex transportIndex, ContactId contactId,
|
||||
BatchTransportReader reader, byte[] encryptedIv) {
|
||||
this.connFactory = connFactory;
|
||||
this.db = db;
|
||||
this.protoFactory = protoFactory;
|
||||
this.transportId = transportId;
|
||||
this.transportIndex = transportIndex;
|
||||
this.contactId = contactId;
|
||||
this.reader = reader;
|
||||
this.encryptedIv = encryptedIv;
|
||||
@@ -49,7 +49,8 @@ class IncomingBatchConnection {
|
||||
try {
|
||||
byte[] secret = db.getSharedSecret(contactId);
|
||||
ConnectionReader conn = connFactory.createConnectionReader(
|
||||
reader.getInputStream(), transportId, encryptedIv, secret);
|
||||
reader.getInputStream(), transportIndex, encryptedIv,
|
||||
secret);
|
||||
ProtocolReader proto = protoFactory.createProtocolReader(
|
||||
conn.getInputStream());
|
||||
// Read packets until EOF
|
||||
|
||||
@@ -8,9 +8,9 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.protocol.writers.AckWriter;
|
||||
import net.sf.briar.api.protocol.writers.BatchWriter;
|
||||
import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
|
||||
@@ -28,18 +28,18 @@ class OutgoingBatchConnection {
|
||||
private final ConnectionWriterFactory connFactory;
|
||||
private final DatabaseComponent db;
|
||||
private final ProtocolWriterFactory protoFactory;
|
||||
private final TransportId transportId;
|
||||
private final TransportIndex transportIndex;
|
||||
private final ContactId contactId;
|
||||
private final BatchTransportWriter writer;
|
||||
|
||||
OutgoingBatchConnection(ConnectionWriterFactory connFactory,
|
||||
DatabaseComponent db, ProtocolWriterFactory protoFactory,
|
||||
TransportId transportId, ContactId contactId,
|
||||
TransportIndex transportIndex, ContactId contactId,
|
||||
BatchTransportWriter writer) {
|
||||
this.connFactory = connFactory;
|
||||
this.db = db;
|
||||
this.protoFactory = protoFactory;
|
||||
this.transportId = transportId;
|
||||
this.transportIndex = transportIndex;
|
||||
this.contactId = contactId;
|
||||
this.writer = writer;
|
||||
}
|
||||
@@ -47,10 +47,10 @@ class OutgoingBatchConnection {
|
||||
void write() {
|
||||
try {
|
||||
byte[] secret = db.getSharedSecret(contactId);
|
||||
long connection = db.getConnectionNumber(contactId, transportId);
|
||||
long connection = db.getConnectionNumber(contactId, transportIndex);
|
||||
ConnectionWriter conn = connFactory.createConnectionWriter(
|
||||
writer.getOutputStream(), writer.getCapacity(), transportId,
|
||||
connection, secret);
|
||||
writer.getOutputStream(), writer.getCapacity(),
|
||||
transportIndex, connection, secret);
|
||||
OutputStream out = conn.getOutputStream();
|
||||
// There should be enough space for a packet
|
||||
long capacity = conn.getRemainingCapacity();
|
||||
|
||||
@@ -3,10 +3,10 @@ package net.sf.briar.transport.stream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.protocol.ProtocolReaderFactory;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
|
||||
import net.sf.briar.api.transport.ConnectionReader;
|
||||
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
||||
@@ -21,11 +21,12 @@ public class IncomingStreamConnection extends StreamConnection {
|
||||
IncomingStreamConnection(ConnectionReaderFactory connReaderFactory,
|
||||
ConnectionWriterFactory connWriterFactory, DatabaseComponent db,
|
||||
ProtocolReaderFactory protoReaderFactory,
|
||||
ProtocolWriterFactory protoWriterFactory, TransportId transportId,
|
||||
ContactId contactId, StreamTransportConnection connection,
|
||||
ProtocolWriterFactory protoWriterFactory,
|
||||
TransportIndex transportIndex, ContactId contactId,
|
||||
StreamTransportConnection connection,
|
||||
byte[] encryptedIv) {
|
||||
super(connReaderFactory, connWriterFactory, db, protoReaderFactory,
|
||||
protoWriterFactory, transportId, contactId, connection);
|
||||
protoWriterFactory, transportIndex, contactId, connection);
|
||||
this.encryptedIv = encryptedIv;
|
||||
}
|
||||
|
||||
@@ -34,7 +35,8 @@ public class IncomingStreamConnection extends StreamConnection {
|
||||
IOException {
|
||||
byte[] secret = db.getSharedSecret(contactId);
|
||||
return connReaderFactory.createConnectionReader(
|
||||
connection.getInputStream(), transportId, encryptedIv, secret);
|
||||
connection.getInputStream(), transportIndex, encryptedIv,
|
||||
secret);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,7 +44,7 @@ public class IncomingStreamConnection extends StreamConnection {
|
||||
IOException {
|
||||
byte[] secret = db.getSharedSecret(contactId);
|
||||
return connWriterFactory.createConnectionWriter(
|
||||
connection.getOutputStream(), Long.MAX_VALUE, transportId,
|
||||
connection.getOutputStream(), Long.MAX_VALUE, transportIndex,
|
||||
encryptedIv, secret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ package net.sf.briar.transport.stream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.protocol.ProtocolReaderFactory;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
|
||||
import net.sf.briar.api.transport.ConnectionReader;
|
||||
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
||||
@@ -21,22 +21,25 @@ public class OutgoingStreamConnection extends StreamConnection {
|
||||
OutgoingStreamConnection(ConnectionReaderFactory connReaderFactory,
|
||||
ConnectionWriterFactory connWriterFactory, DatabaseComponent db,
|
||||
ProtocolReaderFactory protoReaderFactory,
|
||||
ProtocolWriterFactory protoWriterFactory, TransportId transportId,
|
||||
ContactId contactId, StreamTransportConnection connection) {
|
||||
ProtocolWriterFactory protoWriterFactory,
|
||||
TransportIndex transportIndex, ContactId contactId,
|
||||
StreamTransportConnection connection) {
|
||||
super(connReaderFactory, connWriterFactory, db, protoReaderFactory,
|
||||
protoWriterFactory, transportId, contactId, connection);
|
||||
protoWriterFactory, transportIndex, contactId, connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectionReader createConnectionReader() throws DbException,
|
||||
IOException {
|
||||
synchronized(this) {
|
||||
if(connectionNum == -1L)
|
||||
connectionNum = db.getConnectionNumber(contactId, transportId);
|
||||
if(connectionNum == -1L) {
|
||||
connectionNum = db.getConnectionNumber(contactId,
|
||||
transportIndex);
|
||||
}
|
||||
}
|
||||
byte[] secret = db.getSharedSecret(contactId);
|
||||
return connReaderFactory.createConnectionReader(
|
||||
connection.getInputStream(), transportId, connectionNum,
|
||||
connection.getInputStream(), transportIndex, connectionNum,
|
||||
secret);
|
||||
}
|
||||
|
||||
@@ -44,12 +47,14 @@ public class OutgoingStreamConnection extends StreamConnection {
|
||||
protected ConnectionWriter createConnectionWriter() throws DbException,
|
||||
IOException {
|
||||
synchronized(this) {
|
||||
if(connectionNum == -1L)
|
||||
connectionNum = db.getConnectionNumber(contactId, transportId);
|
||||
if(connectionNum == -1L) {
|
||||
connectionNum = db.getConnectionNumber(contactId,
|
||||
transportIndex);
|
||||
}
|
||||
}
|
||||
byte[] secret = db.getSharedSecret(contactId);
|
||||
return connWriterFactory.createConnectionWriter(
|
||||
connection.getOutputStream(), Long.MAX_VALUE, transportId,
|
||||
connection.getOutputStream(), Long.MAX_VALUE, transportIndex,
|
||||
connectionNum, secret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,16 +12,15 @@ import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.FormatException;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.event.BatchReceivedEvent;
|
||||
import net.sf.briar.api.db.event.ContactRemovedEvent;
|
||||
import net.sf.briar.api.db.event.DatabaseEvent;
|
||||
import net.sf.briar.api.db.event.DatabaseListener;
|
||||
import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent;
|
||||
import net.sf.briar.api.db.event.MessagesAddedEvent;
|
||||
import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent;
|
||||
import net.sf.briar.api.db.event.TransportsUpdatedEvent;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.Batch;
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
@@ -30,6 +29,7 @@ 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.TransportIndex;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
import net.sf.briar.api.protocol.writers.AckWriter;
|
||||
import net.sf.briar.api.protocol.writers.BatchWriter;
|
||||
@@ -56,7 +56,7 @@ abstract class StreamConnection implements DatabaseListener {
|
||||
protected final DatabaseComponent db;
|
||||
protected final ProtocolReaderFactory protoReaderFactory;
|
||||
protected final ProtocolWriterFactory protoWriterFactory;
|
||||
protected final TransportId transportId;
|
||||
protected final TransportIndex transportIndex;
|
||||
protected final ContactId contactId;
|
||||
protected final StreamTransportConnection connection;
|
||||
|
||||
@@ -69,14 +69,15 @@ abstract class StreamConnection implements DatabaseListener {
|
||||
StreamConnection(ConnectionReaderFactory connReaderFactory,
|
||||
ConnectionWriterFactory connWriterFactory, DatabaseComponent db,
|
||||
ProtocolReaderFactory protoReaderFactory,
|
||||
ProtocolWriterFactory protoWriterFactory, TransportId transportId,
|
||||
ContactId contactId, StreamTransportConnection connection) {
|
||||
ProtocolWriterFactory protoWriterFactory,
|
||||
TransportIndex transportIndex, ContactId contactId,
|
||||
StreamTransportConnection connection) {
|
||||
this.connReaderFactory = connReaderFactory;
|
||||
this.connWriterFactory = connWriterFactory;
|
||||
this.db = db;
|
||||
this.protoReaderFactory = protoReaderFactory;
|
||||
this.protoWriterFactory = protoWriterFactory;
|
||||
this.transportId = transportId;
|
||||
this.transportIndex = transportIndex;
|
||||
this.contactId = contactId;
|
||||
this.connection = connection;
|
||||
}
|
||||
@@ -108,7 +109,7 @@ abstract class StreamConnection implements DatabaseListener {
|
||||
writerFlags |= Flags.SUBSCRIPTIONS_UPDATED;
|
||||
notifyAll();
|
||||
}
|
||||
} else if(e instanceof TransportsUpdatedEvent) {
|
||||
} else if(e instanceof LocalTransportsUpdatedEvent) {
|
||||
writerFlags |= Flags.TRANSPORTS_UPDATED;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package net.sf.briar.transport.stream;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.protocol.ProtocolReaderFactory;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
|
||||
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
||||
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
||||
@@ -32,11 +32,11 @@ public class StreamConnectionFactoryImpl implements StreamConnectionFactory {
|
||||
this.protoWriterFactory = protoWriterFactory;
|
||||
}
|
||||
|
||||
public void createIncomingConnection(TransportId t, ContactId c,
|
||||
public void createIncomingConnection(TransportIndex i, ContactId c,
|
||||
StreamTransportConnection s, byte[] encryptedIv) {
|
||||
final StreamConnection conn = new IncomingStreamConnection(
|
||||
connReaderFactory, connWriterFactory, db, protoReaderFactory,
|
||||
protoWriterFactory, t, c, s, encryptedIv);
|
||||
protoWriterFactory, i, c, s, encryptedIv);
|
||||
Runnable write = new Runnable() {
|
||||
public void run() {
|
||||
conn.write();
|
||||
@@ -51,11 +51,11 @@ public class StreamConnectionFactoryImpl implements StreamConnectionFactory {
|
||||
new Thread(read).start();
|
||||
}
|
||||
|
||||
public void createOutgoingConnection(TransportId t, ContactId c,
|
||||
public void createOutgoingConnection(TransportIndex i, ContactId c,
|
||||
StreamTransportConnection s) {
|
||||
final StreamConnection conn = new OutgoingStreamConnection(
|
||||
connReaderFactory, connWriterFactory, db, protoReaderFactory,
|
||||
protoWriterFactory, t, c, s);
|
||||
protoWriterFactory, i, c, s);
|
||||
Runnable write = new Runnable() {
|
||||
public void run() {
|
||||
conn.write();
|
||||
|
||||
Reference in New Issue
Block a user