mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +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:
@@ -1,6 +1,9 @@
|
||||
package net.sf.briar.api;
|
||||
|
||||
/** Type-safe wrapper for an integer that uniquely identifies a contact. */
|
||||
/**
|
||||
* Type-safe wrapper for an integer that uniquely identifies a contact within
|
||||
* the scope of a single node.
|
||||
*/
|
||||
public class ContactId {
|
||||
|
||||
private final int id;
|
||||
@@ -23,9 +26,4 @@ public class ContactId {
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
package net.sf.briar.api;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.serial.Writable;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for an integer that uniquely identifies a transport plugin.
|
||||
*/
|
||||
public class TransportId implements Writable {
|
||||
|
||||
public static final int MIN_ID = 0;
|
||||
public static final int MAX_ID = 65535;
|
||||
|
||||
private final int id;
|
||||
|
||||
public TransportId(int id) {
|
||||
if(id < MIN_ID || id > MAX_ID) throw new IllegalArgumentException();
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void writeTo(Writer w) throws IOException {
|
||||
w.writeInt32(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(o instanceof TransportId) return id == ((TransportId) o).id;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -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.event.DatabaseListener;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
@@ -19,6 +18,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;
|
||||
@@ -51,11 +53,10 @@ public interface DatabaseComponent {
|
||||
void removeListener(DatabaseListener d);
|
||||
|
||||
/**
|
||||
* Adds a new contact to the database with the given transport properties
|
||||
* and shared secret, returns an ID for the contact.
|
||||
* Adds a new contact to the database with the given secret and returns an
|
||||
* ID for the contact.
|
||||
*/
|
||||
ContactId addContact(Map<TransportId, TransportProperties> transports,
|
||||
byte[] secret) throws DbException;
|
||||
ContactId addContact(byte[] secret) throws DbException;
|
||||
|
||||
/** Adds a locally generated group message to the database. */
|
||||
void addLocalGroupMessage(Message m) throws DbException;
|
||||
@@ -63,6 +64,12 @@ public interface DatabaseComponent {
|
||||
/** Adds a locally generated private message to the database. */
|
||||
void addLocalPrivateMessage(Message m, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Allocates and returns a local index for the given transport. Returns
|
||||
* null if all indices have been allocated.
|
||||
*/
|
||||
TransportIndex addTransport(TransportId t) throws DbException;
|
||||
|
||||
/**
|
||||
* Generates an acknowledgement for the given contact.
|
||||
* @return True if any batch IDs were added to the acknowledgement.
|
||||
@@ -109,24 +116,29 @@ public interface DatabaseComponent {
|
||||
* Returns an outgoing connection number for the given contact and
|
||||
* transport.
|
||||
*/
|
||||
long getConnectionNumber(ContactId c, TransportId t) throws DbException;
|
||||
long getConnectionNumber(ContactId c, TransportIndex i) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the connection reordering window for the given contact and
|
||||
* transport.
|
||||
*/
|
||||
ConnectionWindow getConnectionWindow(ContactId c, TransportId t)
|
||||
ConnectionWindow getConnectionWindow(ContactId c, TransportIndex i)
|
||||
throws DbException;
|
||||
|
||||
/** Returns the IDs of all contacts. */
|
||||
Collection<ContactId> getContacts() throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the local index for the given transport, or null if no index
|
||||
* has been allocated.
|
||||
*/
|
||||
TransportIndex getLocalIndex(TransportId t) throws DbException;
|
||||
|
||||
/** Returns the local transport properties for the given transport. */
|
||||
TransportProperties getLocalProperties(TransportId t) throws DbException;
|
||||
|
||||
/** Returns all local transport properties. */
|
||||
Map<TransportId, TransportProperties> getLocalTransports()
|
||||
throws DbException;
|
||||
/** Returns all local transports. */
|
||||
Collection<Transport> getLocalTransports() throws DbException;
|
||||
|
||||
/** Returns the headers of all messages in the given group. */
|
||||
Collection<MessageHeader> getMessageHeaders(GroupId g) throws DbException;
|
||||
@@ -134,6 +146,13 @@ public interface DatabaseComponent {
|
||||
/** Returns the user's rating for the given author. */
|
||||
Rating getRating(AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the given contact's index for the given transport, or null if
|
||||
* the contact does not support the transport.
|
||||
*/
|
||||
TransportIndex getRemoteIndex(ContactId c, TransportId t)
|
||||
throws DbException;
|
||||
|
||||
/** Returns all remote transport properties for the given transport. */
|
||||
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
|
||||
throws DbException;
|
||||
@@ -191,8 +210,8 @@ public interface DatabaseComponent {
|
||||
* Sets the connection reordering window for the given contact and
|
||||
* transport.
|
||||
*/
|
||||
void setConnectionWindow(ContactId c, TransportId t, ConnectionWindow w)
|
||||
throws DbException;
|
||||
void setConnectionWindow(ContactId c, TransportIndex i,
|
||||
ConnectionWindow w) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the local transport properties for the given transport, replacing
|
||||
|
||||
@@ -3,9 +3,15 @@ package net.sf.briar.api.db.event;
|
||||
import net.sf.briar.api.ContactId;
|
||||
|
||||
/** An event that is broadcast when a contact is removed. */
|
||||
public class ContactRemovedEvent extends ContactAddedEvent {
|
||||
public class ContactRemovedEvent extends DatabaseEvent {
|
||||
|
||||
private final ContactId contactId;
|
||||
|
||||
public ContactRemovedEvent(ContactId contactId) {
|
||||
super(contactId);
|
||||
this.contactId = contactId;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.sf.briar.api.db.event;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when the local transport properties are
|
||||
* updated.
|
||||
*/
|
||||
public class LocalTransportsUpdatedEvent extends DatabaseEvent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.sf.briar.api.db.event;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
|
||||
/** An event that is broadcast when a contact's transports are updated. */
|
||||
public class RemoteTransportsUpdatedEvent extends DatabaseEvent {
|
||||
|
||||
private final ContactId contactId;
|
||||
|
||||
public RemoteTransportsUpdatedEvent(ContactId contactId) {
|
||||
this.contactId = contactId;
|
||||
}
|
||||
|
||||
public ContactId getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
}
|
||||
17
api/net/sf/briar/api/db/event/TransportAddedEvent.java
Normal file
17
api/net/sf/briar/api/db/event/TransportAddedEvent.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package net.sf.briar.api.db.event;
|
||||
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
|
||||
/** An event that is broadcast when a transport is added. */
|
||||
public class TransportAddedEvent extends DatabaseEvent {
|
||||
|
||||
private final TransportId transportId;
|
||||
|
||||
public TransportAddedEvent(TransportId transportId) {
|
||||
this.transportId = transportId;
|
||||
}
|
||||
|
||||
public TransportId getTransportId() {
|
||||
return transportId;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package net.sf.briar.api.db.event;
|
||||
|
||||
/** An event that is broadcast when the local transports are updated. */
|
||||
public class TransportsUpdatedEvent extends DatabaseEvent {
|
||||
|
||||
}
|
||||
@@ -4,6 +4,5 @@ import java.util.concurrent.Executor;
|
||||
|
||||
public interface BatchPluginFactory {
|
||||
|
||||
BatchPlugin createPlugin(Executor executor,
|
||||
BatchPluginCallback callback);
|
||||
BatchPlugin createPlugin(Executor executor, BatchPluginCallback callback);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.sf.briar.api.plugins;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
|
||||
public interface Plugin {
|
||||
|
||||
|
||||
@@ -3,14 +3,13 @@ package net.sf.briar.api.plugins;
|
||||
public interface PluginManager {
|
||||
|
||||
/**
|
||||
* Starts all the plugins the manager knows about and returns the number of
|
||||
* plugins successfully started.
|
||||
* Starts the plugins and returns the number of plugins successfully
|
||||
* started.
|
||||
*/
|
||||
int startPlugins();
|
||||
|
||||
/**
|
||||
* Stops all the plugins started by startPlugins() and returns the number
|
||||
* of plugins successfully stopped.
|
||||
* Stops the plugins and returns the number of plugins successfully stopped.
|
||||
*/
|
||||
int stopPlugins();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,5 @@ import java.util.concurrent.Executor;
|
||||
|
||||
public interface StreamPluginFactory {
|
||||
|
||||
StreamPlugin createPlugin(Executor executor,
|
||||
StreamPluginCallback callback);
|
||||
StreamPlugin createPlugin(Executor executor, StreamPluginCallback callback);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
import net.sf.briar.api.serial.Writable;
|
||||
|
||||
/** A pseudonymous author of messages. */
|
||||
public interface Author extends Writable {
|
||||
|
||||
/** The maximum length of an author's name in UTF-8 bytes. */
|
||||
static final int MAX_NAME_LENGTH = 50;
|
||||
|
||||
/** The maximum length of an author's public key in bytes. */
|
||||
static final int MAX_PUBLIC_KEY_LENGTH = 100;
|
||||
public interface Author {
|
||||
|
||||
/** Returns the author's unique identifier. */
|
||||
AuthorId getId();
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
/** Type-safe wrapper for a byte array that uniquely identifies an author. */
|
||||
public class AuthorId extends UniqueId {
|
||||
|
||||
@@ -12,11 +9,6 @@ public class AuthorId extends UniqueId {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public void writeTo(Writer w) throws IOException {
|
||||
w.writeUserDefinedId(Types.AUTHOR_ID);
|
||||
w.writeBytes(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(o instanceof AuthorId)
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for a byte array that uniquely identifies a batch of
|
||||
* messages.
|
||||
@@ -15,11 +12,6 @@ public class BatchId extends UniqueId {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public void writeTo(Writer w) throws IOException {
|
||||
w.writeUserDefinedId(Types.BATCH_ID);
|
||||
w.writeBytes(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(o instanceof BatchId)
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
import net.sf.briar.api.serial.Writable;
|
||||
|
||||
/** A group to which users may subscribe. */
|
||||
public interface Group extends Writable {
|
||||
|
||||
/** The maximum length of a group's name in UTF-8 bytes. */
|
||||
static final int MAX_NAME_LENGTH = 50;
|
||||
|
||||
/** The maximum length of a group's public key in bytes. */
|
||||
static final int MAX_PUBLIC_KEY_LENGTH = 100;
|
||||
public interface Group {
|
||||
|
||||
/** Returns the group's unique identifier. */
|
||||
GroupId getId();
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for a byte array that uniquely identifies a group to which
|
||||
* users may subscribe.
|
||||
@@ -15,11 +12,6 @@ public class GroupId extends UniqueId {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public void writeTo(Writer w) throws IOException {
|
||||
w.writeUserDefinedId(Types.GROUP_ID);
|
||||
w.writeBytes(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(o instanceof GroupId)
|
||||
|
||||
@@ -2,23 +2,6 @@ package net.sf.briar.api.protocol;
|
||||
|
||||
public interface Message {
|
||||
|
||||
/**
|
||||
* The maximum length of a message body in bytes. To allow for future
|
||||
* changes in the protocol, this is smaller than the maximum packet length
|
||||
* even when all the message's other fields have their maximum lengths.
|
||||
*/
|
||||
static final int MAX_BODY_LENGTH =
|
||||
ProtocolConstants.MAX_PACKET_LENGTH - 1024;
|
||||
|
||||
/** The maximum length of a subject line in UTF-8 bytes. */
|
||||
static final int MAX_SUBJECT_LENGTH = 100;
|
||||
|
||||
/** The maximum length of a signature in bytes. */
|
||||
static final int MAX_SIGNATURE_LENGTH = 100;
|
||||
|
||||
/** The length of the random salt in bytes. */
|
||||
static final int SALT_LENGTH = 8;
|
||||
|
||||
/** Returns the message's unique identifier. */
|
||||
MessageId getId();
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
/** Type-safe wrapper for a byte array that uniquely identifies a message. */
|
||||
public class MessageId extends UniqueId {
|
||||
|
||||
@@ -12,11 +9,6 @@ public class MessageId extends UniqueId {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public void writeTo(Writer w) throws IOException {
|
||||
w.writeUserDefinedId(Types.MESSAGE_ID);
|
||||
w.writeBytes(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(o instanceof MessageId)
|
||||
|
||||
@@ -11,4 +11,41 @@ public interface ProtocolConstants {
|
||||
*/
|
||||
static final int MAX_PACKET_LENGTH =
|
||||
TransportConstants.MIN_CONNECTION_LENGTH - 1024;
|
||||
|
||||
/** The maximum number of transport plugins a node may support. */
|
||||
static final int MAX_TRANSPORTS = 50;
|
||||
|
||||
/** The maximum number of properties per transport plugin. */
|
||||
static final int MAX_PROPERTIES_PER_TRANSPORT = 100;
|
||||
|
||||
/** The maximum length of a property's key or value in UTF-8 bytes. */
|
||||
static final int MAX_PROPERTY_LENGTH = 100;
|
||||
|
||||
/** The maximum number of groups a node may subscribe to. */
|
||||
static final int MAX_GROUPS = 6000;
|
||||
|
||||
/** The maximum length of a group's name in UTF-8 bytes. */
|
||||
static final int MAX_GROUP_NAME_LENGTH = 50;
|
||||
|
||||
/** The maximum length of a serialised public key in bytes. */
|
||||
static final int MAX_PUBLIC_KEY_LENGTH = 100;
|
||||
|
||||
/** The maximum length of an author's name in UTF-8 bytes. */
|
||||
static final int MAX_AUTHOR_NAME_LENGTH = 50;
|
||||
|
||||
/**
|
||||
* The maximum length of a message body in bytes. To allow for future
|
||||
* changes in the protocol, this is smaller than the maximum packet length
|
||||
* even when all the message's other fields have their maximum lengths.
|
||||
*/
|
||||
static final int MAX_BODY_LENGTH = MAX_PACKET_LENGTH - 1024;
|
||||
|
||||
/** The maximum length of a message's subject line in UTF-8 bytes. */
|
||||
static final int MAX_SUBJECT_LENGTH = 100;
|
||||
|
||||
/** The maximum length of a signature in bytes. */
|
||||
static final int MAX_SIGNATURE_LENGTH = 100;
|
||||
|
||||
/** The length of a message's random salt in bytes. */
|
||||
static final int SALT_LENGTH = 8;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,6 @@ import java.util.Map;
|
||||
/** A packet updating the sender's subscriptions. */
|
||||
public interface SubscriptionUpdate {
|
||||
|
||||
/** The maximum number of subscriptions per update. */
|
||||
static final int MAX_SUBS_PER_UPDATE = 6000;
|
||||
|
||||
/** Returns the subscriptions contained in the update. */
|
||||
Map<Group, Long> getSubscriptions();
|
||||
|
||||
|
||||
47
api/net/sf/briar/api/protocol/Transport.java
Normal file
47
api/net/sf/briar/api/protocol/Transport.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class Transport extends TreeMap<String, String> {
|
||||
|
||||
private static final long serialVersionUID = 4900420175715429560L;
|
||||
|
||||
private final TransportId id;
|
||||
private final TransportIndex index;
|
||||
|
||||
public Transport(TransportId id, TransportIndex index,
|
||||
Map<String, String> p) {
|
||||
super(p);
|
||||
this.id = id;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public Transport(TransportId id, TransportIndex index) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public TransportId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public TransportIndex getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(o instanceof Transport) {
|
||||
Transport t = (Transport) o;
|
||||
return id.equals(t.id) && index.equals(t.index) && super.equals(o);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
21
api/net/sf/briar/api/protocol/TransportId.java
Normal file
21
api/net/sf/briar/api/protocol/TransportId.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for a byte array that uniquely identifies a transport
|
||||
* plugin.
|
||||
*/
|
||||
public class TransportId extends UniqueId {
|
||||
|
||||
public TransportId(byte[] id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(o instanceof TransportId)
|
||||
return Arrays.equals(id, ((TransportId) o).id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
33
api/net/sf/briar/api/protocol/TransportIndex.java
Normal file
33
api/net/sf/briar/api/protocol/TransportIndex.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
|
||||
/**
|
||||
* Type-safe wrapper for an integer that uniquely identifies a transport plugin
|
||||
* within the scope of a single node.
|
||||
*/
|
||||
public class TransportIndex {
|
||||
|
||||
private final int index;
|
||||
|
||||
public TransportIndex(int index) {
|
||||
if(index < 0 || index >= ProtocolConstants.MAX_TRANSPORTS)
|
||||
throw new IllegalArgumentException();
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(o instanceof TransportIndex)
|
||||
return index == ((TransportIndex) o).index;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,12 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import java.util.Collection;
|
||||
|
||||
/** A packet updating the sender's transport properties. */
|
||||
public interface TransportUpdate {
|
||||
|
||||
/** The maximum length of a property's key or value in UTF-8 bytes. */
|
||||
static final int MAX_KEY_OR_VALUE_LENGTH = 100;
|
||||
|
||||
/** The maximum number of properties per plugin. */
|
||||
static final int MAX_PROPERTIES_PER_PLUGIN = 100;
|
||||
|
||||
/** The maximum number of plugins per update. */
|
||||
static final int MAX_PLUGINS_PER_UPDATE = 50;
|
||||
|
||||
/** Returns the transport properties contained in the update. */
|
||||
Map<TransportId, TransportProperties> getTransports();
|
||||
/** Returns the transports contained in the update. */
|
||||
Collection<Transport> getTransports();
|
||||
|
||||
/**
|
||||
* Returns the update's timestamp. Updates that are older than the newest
|
||||
|
||||
@@ -5,16 +5,14 @@ public interface Types {
|
||||
|
||||
static final int ACK = 0;
|
||||
static final int AUTHOR = 1;
|
||||
static final int AUTHOR_ID = 2;
|
||||
static final int BATCH = 3;
|
||||
static final int BATCH_ID = 4;
|
||||
static final int GROUP = 5;
|
||||
static final int GROUP_ID = 6;
|
||||
static final int MESSAGE = 7;
|
||||
static final int MESSAGE_ID = 8;
|
||||
static final int OFFER = 9;
|
||||
static final int REQUEST = 10;
|
||||
static final int SUBSCRIPTION_UPDATE = 11;
|
||||
static final int TRANSPORT_PROPERTIES = 12;
|
||||
static final int TRANSPORT_UPDATE = 13;
|
||||
static final int BATCH = 2;
|
||||
static final int BATCH_ID = 3;
|
||||
static final int GROUP = 4;
|
||||
static final int MESSAGE = 5;
|
||||
static final int MESSAGE_ID = 6;
|
||||
static final int OFFER = 7;
|
||||
static final int REQUEST = 8;
|
||||
static final int SUBSCRIPTION_UPDATE = 9;
|
||||
static final int TRANSPORT = 10;
|
||||
static final int TRANSPORT_UPDATE = 11;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@ package net.sf.briar.api.protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.sf.briar.api.serial.Writable;
|
||||
|
||||
public abstract class UniqueId implements Writable {
|
||||
public abstract class UniqueId {
|
||||
|
||||
/** The length of a unique identifier in bytes. */
|
||||
public static final int LENGTH = 32;
|
||||
|
||||
11
api/net/sf/briar/api/protocol/writers/AuthorWriter.java
Normal file
11
api/net/sf/briar/api/protocol/writers/AuthorWriter.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package net.sf.briar.api.protocol.writers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.protocol.Author;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
public interface AuthorWriter {
|
||||
|
||||
void writeAuthor(Writer w, Author a) throws IOException;
|
||||
}
|
||||
11
api/net/sf/briar/api/protocol/writers/GroupWriter.java
Normal file
11
api/net/sf/briar/api/protocol/writers/GroupWriter.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package net.sf.briar.api.protocol.writers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
public interface GroupWriter {
|
||||
|
||||
void writeGroup(Writer w, Group g) throws IOException;
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
package net.sf.briar.api.protocol;
|
||||
package net.sf.briar.api.protocol.writers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PrivateKey;
|
||||
|
||||
import net.sf.briar.api.protocol.Author;
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.Message;
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
|
||||
public interface MessageEncoder {
|
||||
|
||||
/** Encodes a private message. */
|
||||
@@ -1,15 +1,14 @@
|
||||
package net.sf.briar.api.protocol.writers;
|
||||
|
||||
import java.io.IOException;
|
||||
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;
|
||||
|
||||
/** An interface for creating a transport update. */
|
||||
public interface TransportWriter {
|
||||
|
||||
/** Writes the contents of the update. */
|
||||
void writeTransports(Map<TransportId, TransportProperties> transports,
|
||||
long timestamp) throws IOException;
|
||||
void writeTransports(Collection<Transport> transports, long timestamp)
|
||||
throws IOException;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package net.sf.briar.api.serial;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Writable {
|
||||
|
||||
void writeTo(Writer w) throws IOException;
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
package net.sf.briar.api.transport;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
|
||||
public interface BatchConnectionFactory {
|
||||
|
||||
void createIncomingConnection(TransportId t, ContactId c,
|
||||
void createIncomingConnection(TransportIndex i, ContactId c,
|
||||
BatchTransportReader r, byte[] encryptedIv);
|
||||
|
||||
void createOutgoingConnection(TransportId t, ContactId c,
|
||||
void createOutgoingConnection(TransportIndex i, ContactId c,
|
||||
BatchTransportWriter w);
|
||||
}
|
||||
|
||||
16
api/net/sf/briar/api/transport/ConnectionContext.java
Normal file
16
api/net/sf/briar/api/transport/ConnectionContext.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package net.sf.briar.api.transport;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
|
||||
public interface ConnectionContext {
|
||||
|
||||
ContactId getContactId();
|
||||
|
||||
TransportId getTransportId();
|
||||
|
||||
TransportIndex getTransportIndex();
|
||||
|
||||
long getConnectionNumber();
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
package net.sf.briar.api.transport;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
|
||||
public interface ConnectionDispatcher {
|
||||
|
||||
void dispatchReader(TransportId t, BatchTransportReader r);
|
||||
|
||||
void dispatchWriter(TransportId t, ContactId c,
|
||||
BatchTransportWriter w);
|
||||
void dispatchWriter(TransportIndex i, ContactId c, BatchTransportWriter w);
|
||||
|
||||
void dispatchIncomingConnection(TransportId t, StreamTransportConnection s);
|
||||
|
||||
void dispatchOutgoingConnection(TransportId t, ContactId c,
|
||||
void dispatchOutgoingConnection(TransportIndex i, ContactId c,
|
||||
StreamTransportConnection s);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.sf.briar.api.transport;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
|
||||
public interface ConnectionReaderFactory {
|
||||
|
||||
@@ -10,13 +10,13 @@ public interface ConnectionReaderFactory {
|
||||
* Creates a connection reader for a batch-mode connection or the
|
||||
* initiator's side of a stream-mode connection.
|
||||
*/
|
||||
ConnectionReader createConnectionReader(InputStream in, TransportId t,
|
||||
ConnectionReader createConnectionReader(InputStream in, TransportIndex i,
|
||||
byte[] encryptedIv, byte[] secret);
|
||||
|
||||
/**
|
||||
* Creates a connection reader for the responder's side of a stream-mode
|
||||
* connection.
|
||||
*/
|
||||
ConnectionReader createConnectionReader(InputStream in, TransportId t,
|
||||
ConnectionReader createConnectionReader(InputStream in, TransportIndex i,
|
||||
long connection, byte[] secret);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
package net.sf.briar.api.transport;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
|
||||
/**
|
||||
* Maintains a transport plugin's connection reordering window and decides
|
||||
* whether incoming connections should be accepted or rejected.
|
||||
* Maintains the connection reordering windows and decides whether incoming
|
||||
* connections should be accepted or rejected.
|
||||
*/
|
||||
public interface ConnectionRecogniser {
|
||||
|
||||
/**
|
||||
* Returns the ID of the contact who created the encrypted IV if the
|
||||
* connection should be accepted, or null if the connection should be
|
||||
* rejected.
|
||||
* Returns the connection's context if the connection should be accepted,
|
||||
* or null if the connection should be rejected.
|
||||
*/
|
||||
ContactId acceptConnection(byte[] encryptedIv) throws DbException;
|
||||
ConnectionContext acceptConnection(byte[] encryptedIv) throws DbException;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package net.sf.briar.api.transport;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
|
||||
public interface ConnectionRecogniserFactory {
|
||||
|
||||
ConnectionRecogniser createConnectionRecogniser(TransportId t);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package net.sf.briar.api.transport;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
|
||||
public interface ConnectionWriterFactory {
|
||||
|
||||
@@ -11,12 +11,12 @@ public interface ConnectionWriterFactory {
|
||||
* initiator's side of a stream-mode connection.
|
||||
*/
|
||||
ConnectionWriter createConnectionWriter(OutputStream out, long capacity,
|
||||
TransportId t, long connection, byte[] secret);
|
||||
TransportIndex i, long connection, byte[] secret);
|
||||
|
||||
/**
|
||||
* Creates a connection writer for the responder's side of a stream-mode
|
||||
* connection.
|
||||
*/
|
||||
ConnectionWriter createConnectionWriter(OutputStream out, long capacity,
|
||||
TransportId t, byte[] encryptedIv, byte[] secret);
|
||||
TransportIndex i, byte[] encryptedIv, byte[] secret);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package net.sf.briar.api.transport;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.protocol.TransportIndex;
|
||||
|
||||
public interface StreamConnectionFactory {
|
||||
|
||||
void createIncomingConnection(TransportId t, ContactId c,
|
||||
void createIncomingConnection(TransportIndex i, ContactId c,
|
||||
StreamTransportConnection s, byte[] encryptedIv);
|
||||
|
||||
void createOutgoingConnection(TransportId t, ContactId c,
|
||||
void createOutgoingConnection(TransportIndex i, ContactId c,
|
||||
StreamTransportConnection s);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -15,8 +15,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.briar.api.TransportId;
|
||||
import net.sf.briar.api.TransportProperties;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.Author;
|
||||
@@ -26,17 +24,20 @@ 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.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.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.UniqueId;
|
||||
import net.sf.briar.api.protocol.writers.AckWriter;
|
||||
import net.sf.briar.api.protocol.writers.BatchWriter;
|
||||
import net.sf.briar.api.protocol.writers.MessageEncoder;
|
||||
import net.sf.briar.api.protocol.writers.OfferWriter;
|
||||
import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
|
||||
import net.sf.briar.api.protocol.writers.RequestWriter;
|
||||
@@ -52,6 +53,8 @@ import net.sf.briar.protocol.ProtocolModule;
|
||||
import net.sf.briar.protocol.writers.ProtocolWritersModule;
|
||||
import net.sf.briar.serial.SerialModule;
|
||||
import net.sf.briar.transport.TransportModule;
|
||||
import net.sf.briar.transport.batch.TransportBatchModule;
|
||||
import net.sf.briar.transport.stream.TransportStreamModule;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -69,7 +72,7 @@ public class ProtocolIntegrationTest extends TestCase {
|
||||
private final ProtocolWriterFactory protocolWriterFactory;
|
||||
private final CryptoComponent crypto;
|
||||
private final byte[] aliceSecret, bobSecret;
|
||||
private final TransportId transportId = new TransportId(123);
|
||||
private final TransportIndex transportIndex = new TransportIndex(13);
|
||||
private final long connection = 12345L;
|
||||
private final Author author;
|
||||
private final Group group, group1;
|
||||
@@ -77,14 +80,15 @@ public class ProtocolIntegrationTest extends TestCase {
|
||||
private final String authorName = "Alice";
|
||||
private final String subject = "Hello";
|
||||
private final String messageBody = "Hello world";
|
||||
private final Map<TransportId, TransportProperties> transports;
|
||||
private final Collection<Transport> transports;
|
||||
|
||||
public ProtocolIntegrationTest() throws Exception {
|
||||
super();
|
||||
Injector i = Guice.createInjector(new CryptoModule(),
|
||||
new DatabaseModule(), new ProtocolModule(),
|
||||
new ProtocolWritersModule(), new SerialModule(),
|
||||
new TestDatabaseModule(), new TransportModule());
|
||||
new TestDatabaseModule(), new TransportBatchModule(),
|
||||
new TransportModule(), new TransportStreamModule());
|
||||
connectionReaderFactory = i.getInstance(ConnectionReaderFactory.class);
|
||||
connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class);
|
||||
protocolReaderFactory = i.getInstance(ProtocolReaderFactory.class);
|
||||
@@ -120,9 +124,11 @@ public class ProtocolIntegrationTest extends TestCase {
|
||||
message3 = messageEncoder.encodeMessage(null, group1,
|
||||
groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(),
|
||||
subject, messageBody.getBytes("UTF-8"));
|
||||
TransportProperties p =
|
||||
new TransportProperties(Collections.singletonMap("bar", "baz"));
|
||||
transports = Collections.singletonMap(transportId, p);
|
||||
// Create some transports
|
||||
TransportId transportId = new TransportId(TestUtils.getRandomId());
|
||||
Transport transport = new Transport(transportId, transportIndex,
|
||||
Collections.singletonMap("bar", "baz"));
|
||||
transports = Collections.singletonList(transport);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -134,7 +140,7 @@ public class ProtocolIntegrationTest extends TestCase {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
// Use Alice's secret for writing
|
||||
ConnectionWriter w = connectionWriterFactory.createConnectionWriter(out,
|
||||
Long.MAX_VALUE, transportId, connection, aliceSecret);
|
||||
Long.MAX_VALUE, transportIndex, connection, aliceSecret);
|
||||
OutputStream out1 = w.getOutputStream();
|
||||
|
||||
AckWriter a = protocolWriterFactory.createAckWriter(out1);
|
||||
@@ -188,7 +194,7 @@ public class ProtocolIntegrationTest extends TestCase {
|
||||
assertEquals(16, offset);
|
||||
// Use Bob's secret for reading
|
||||
ConnectionReader r = connectionReaderFactory.createConnectionReader(in,
|
||||
transportId, encryptedIv, bobSecret);
|
||||
transportIndex, encryptedIv, bobSecret);
|
||||
in = r.getInputStream();
|
||||
ProtocolReader protocolReader =
|
||||
protocolReaderFactory.createProtocolReader(in);
|
||||
|
||||
@@ -48,7 +48,7 @@ public class DatabaseComponentImplTest extends DatabaseComponentTest {
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
oneOf(database).getOldMessages(txn, BYTES_PER_SWEEP);
|
||||
will(returnValue(Collections.emptySet()));
|
||||
will(returnValue(Collections.emptyList()));
|
||||
oneOf(database).commitTransaction(txn);
|
||||
// As if by magic, some free space has appeared
|
||||
oneOf(database).getFreeSpace();
|
||||
|
||||
@@ -10,7 +10,6 @@ import junit.framework.TestCase;
|
||||
import net.sf.briar.TestUtils;
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.Rating;
|
||||
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.MessageHeader;
|
||||
@@ -21,7 +20,7 @@ import net.sf.briar.api.db.event.ContactRemovedEvent;
|
||||
import net.sf.briar.api.db.event.DatabaseListener;
|
||||
import net.sf.briar.api.db.event.MessagesAddedEvent;
|
||||
import net.sf.briar.api.db.event.RatingChangedEvent;
|
||||
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;
|
||||
@@ -33,6 +32,9 @@ import net.sf.briar.api.protocol.MessageId;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
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;
|
||||
@@ -61,7 +63,8 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
private final Message message, privateMessage;
|
||||
private final Group group;
|
||||
private final TransportId transportId;
|
||||
private final Map<TransportId, TransportProperties> transports;
|
||||
private final TransportIndex localIndex, remoteIndex;
|
||||
private final Collection<Transport> transports;
|
||||
private final Map<ContactId, TransportProperties> remoteProperties;
|
||||
private final byte[] secret;
|
||||
|
||||
@@ -82,11 +85,15 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
privateMessage = new TestMessage(messageId, null, null, null, subject,
|
||||
timestamp, raw);
|
||||
group = new TestGroup(groupId, "The really exciting group", null);
|
||||
transportId = new TransportId(123);
|
||||
TransportProperties p =
|
||||
new TransportProperties(Collections.singletonMap("foo", "bar"));
|
||||
transports = Collections.singletonMap(transportId, p);
|
||||
remoteProperties = Collections.singletonMap(contactId, p);
|
||||
transportId = new TransportId(TestUtils.getRandomId());
|
||||
localIndex = new TransportIndex(0);
|
||||
remoteIndex = new TransportIndex(13);
|
||||
TransportProperties properties = new TransportProperties(
|
||||
Collections.singletonMap("foo", "bar"));
|
||||
remoteProperties = Collections.singletonMap(contactId, properties);
|
||||
Transport transport = new Transport(transportId, localIndex,
|
||||
properties);
|
||||
transports = Collections.singletonList(transport);
|
||||
secret = new byte[123];
|
||||
}
|
||||
|
||||
@@ -124,17 +131,17 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
// setRating(authorId, Rating.GOOD) again
|
||||
oneOf(database).setRating(txn, authorId, Rating.GOOD);
|
||||
will(returnValue(Rating.GOOD));
|
||||
// addContact(transports)
|
||||
oneOf(database).addContact(txn, transports, secret);
|
||||
// addContact()
|
||||
oneOf(database).addContact(txn, secret);
|
||||
will(returnValue(contactId));
|
||||
oneOf(listener).eventOccurred(with(any(ContactAddedEvent.class)));
|
||||
// getContacts()
|
||||
oneOf(database).getContacts(txn);
|
||||
will(returnValue(Collections.singletonList(contactId)));
|
||||
// getConnectionWindow(contactId, 123)
|
||||
// getConnectionWindow(contactId, 13)
|
||||
oneOf(database).containsContact(txn, contactId);
|
||||
will(returnValue(true));
|
||||
oneOf(database).getConnectionWindow(txn, contactId, transportId);
|
||||
oneOf(database).getConnectionWindow(txn, contactId, remoteIndex);
|
||||
will(returnValue(connectionWindow));
|
||||
// getSharedSecret(contactId)
|
||||
oneOf(database).containsContact(txn, contactId);
|
||||
@@ -170,10 +177,10 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
// unsubscribe(groupId) again
|
||||
oneOf(database).containsSubscription(txn, groupId);
|
||||
will(returnValue(false));
|
||||
// setConnectionWindow(contactId, 123, connectionWindow)
|
||||
// setConnectionWindow(contactId, 13, connectionWindow)
|
||||
oneOf(database).containsContact(txn, contactId);
|
||||
will(returnValue(true));
|
||||
oneOf(database).setConnectionWindow(txn, contactId, transportId,
|
||||
oneOf(database).setConnectionWindow(txn, contactId, remoteIndex,
|
||||
connectionWindow);
|
||||
// removeContact(contactId)
|
||||
oneOf(database).removeContact(txn, contactId);
|
||||
@@ -189,10 +196,10 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
assertEquals(Rating.UNRATED, db.getRating(authorId));
|
||||
db.setRating(authorId, Rating.GOOD); // First time - listeners called
|
||||
db.setRating(authorId, Rating.GOOD); // Second time - not called
|
||||
assertEquals(contactId, db.addContact(transports, secret));
|
||||
assertEquals(contactId, db.addContact(secret));
|
||||
assertEquals(Collections.singletonList(contactId), db.getContacts());
|
||||
assertEquals(connectionWindow,
|
||||
db.getConnectionWindow(contactId, transportId));
|
||||
db.getConnectionWindow(contactId, remoteIndex));
|
||||
assertEquals(secret, db.getSharedSecret(contactId));
|
||||
assertEquals(remoteProperties, db.getRemoteProperties(transportId));
|
||||
db.subscribe(group); // First time - listeners called
|
||||
@@ -201,7 +208,7 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
assertEquals(Collections.singletonList(groupId), db.getSubscriptions());
|
||||
db.unsubscribe(groupId); // First time - listeners called
|
||||
db.unsubscribe(groupId); // Second time - not called
|
||||
db.setConnectionWindow(contactId, transportId, connectionWindow);
|
||||
db.setConnectionWindow(contactId, remoteIndex, connectionWindow);
|
||||
db.removeContact(contactId);
|
||||
db.removeListener(listener);
|
||||
db.close();
|
||||
@@ -540,7 +547,7 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
} catch(NoSuchContactException expected) {}
|
||||
|
||||
try {
|
||||
db.getConnectionWindow(contactId, transportId);
|
||||
db.getConnectionWindow(contactId, remoteIndex);
|
||||
fail();
|
||||
} catch(NoSuchContactException expected) {}
|
||||
|
||||
@@ -580,7 +587,7 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
} catch(NoSuchContactException expected) {}
|
||||
|
||||
try {
|
||||
db.setConnectionWindow(contactId, transportId, null);
|
||||
db.setConnectionWindow(contactId, remoteIndex, null);
|
||||
fail();
|
||||
} catch(NoSuchContactException expected) {}
|
||||
|
||||
@@ -1379,7 +1386,7 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
with(any(long.class)));
|
||||
oneOf(database).commitTransaction(txn);
|
||||
oneOf(listener).eventOccurred(with(any(
|
||||
TransportsUpdatedEvent.class)));
|
||||
TransportAddedEvent.class)));
|
||||
}});
|
||||
DatabaseComponent db = createDatabaseComponent(database, cleaner);
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -22,7 +21,6 @@ import net.sf.briar.TestUtils;
|
||||
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.crypto.Password;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
@@ -35,12 +33,18 @@ 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.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.crypto.CryptoModule;
|
||||
import net.sf.briar.protocol.ProtocolModule;
|
||||
import net.sf.briar.protocol.writers.ProtocolWritersModule;
|
||||
import net.sf.briar.serial.SerialModule;
|
||||
import net.sf.briar.transport.TransportModule;
|
||||
import net.sf.briar.transport.batch.TransportBatchModule;
|
||||
import net.sf.briar.transport.stream.TransportStreamModule;
|
||||
|
||||
import org.apache.commons.io.FileSystemUtils;
|
||||
import org.junit.After;
|
||||
@@ -75,17 +79,20 @@ public class H2DatabaseTest extends TestCase {
|
||||
private final Message message, privateMessage;
|
||||
private final Group group;
|
||||
private final TransportId transportId;
|
||||
private final TransportIndex localIndex, remoteIndex;
|
||||
private final TransportProperties properties;
|
||||
private final Map<TransportId, TransportProperties> transports;
|
||||
private final Map<ContactId, TransportProperties> remoteProperties;
|
||||
private final Collection<Transport> remoteTransports;
|
||||
private final Map<Group, Long> subscriptions;
|
||||
private final byte[] secret;
|
||||
|
||||
public H2DatabaseTest() throws Exception {
|
||||
super();
|
||||
Injector i = Guice.createInjector(new CryptoModule(),
|
||||
new DatabaseModule(), new ProtocolModule(), new SerialModule(),
|
||||
new TransportModule(), new TestDatabaseModule(testDir));
|
||||
new DatabaseModule(), new ProtocolModule(),
|
||||
new ProtocolWritersModule(), new SerialModule(),
|
||||
new TransportBatchModule(), new TransportModule(),
|
||||
new TransportStreamModule(), new TestDatabaseModule(testDir));
|
||||
connectionWindowFactory = i.getInstance(ConnectionWindowFactory.class);
|
||||
groupFactory = i.getInstance(GroupFactory.class);
|
||||
authorId = new AuthorId(TestUtils.getRandomId());
|
||||
@@ -104,11 +111,15 @@ public class H2DatabaseTest extends TestCase {
|
||||
privateMessage = new TestMessage(privateMessageId, null, null, null,
|
||||
subject, timestamp, raw);
|
||||
group = groupFactory.createGroup(groupId, "Group name", null);
|
||||
transportId = new TransportId(0);
|
||||
transportId = new TransportId(TestUtils.getRandomId());
|
||||
localIndex = new TransportIndex(1);
|
||||
remoteIndex = new TransportIndex(13);
|
||||
properties = new TransportProperties(
|
||||
Collections.singletonMap("foo", "bar"));
|
||||
transports = Collections.singletonMap(transportId, properties);
|
||||
remoteProperties = Collections.singletonMap(contactId, properties);
|
||||
Transport remoteTransport = new Transport(transportId, remoteIndex,
|
||||
properties);
|
||||
remoteTransports = Collections.singletonList(remoteTransport);
|
||||
subscriptions = Collections.singletonMap(group, 0L);
|
||||
secret = new byte[123];
|
||||
}
|
||||
@@ -124,7 +135,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Database<Connection> db = open(false);
|
||||
Connection txn = db.startTransaction();
|
||||
assertFalse(db.containsContact(txn, contactId));
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
assertTrue(db.containsContact(txn, contactId));
|
||||
assertFalse(db.containsSubscription(txn, groupId));
|
||||
db.addSubscription(txn, group);
|
||||
@@ -142,8 +153,6 @@ public class H2DatabaseTest extends TestCase {
|
||||
db = open(true);
|
||||
txn = db.startTransaction();
|
||||
assertTrue(db.containsContact(txn, contactId));
|
||||
assertEquals(remoteProperties,
|
||||
db.getRemoteProperties(txn, transportId));
|
||||
assertTrue(db.containsSubscription(txn, groupId));
|
||||
assertTrue(db.containsMessage(txn, messageId));
|
||||
byte[] raw1 = db.getMessage(txn, messageId);
|
||||
@@ -182,20 +191,20 @@ public class H2DatabaseTest extends TestCase {
|
||||
|
||||
// Create three contacts
|
||||
assertFalse(db.containsContact(txn, contactId));
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
assertTrue(db.containsContact(txn, contactId));
|
||||
assertFalse(db.containsContact(txn, contactId1));
|
||||
assertEquals(contactId1, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId1, db.addContact(txn, secret));
|
||||
assertTrue(db.containsContact(txn, contactId1));
|
||||
assertFalse(db.containsContact(txn, contactId2));
|
||||
assertEquals(contactId2, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId2, db.addContact(txn, secret));
|
||||
assertTrue(db.containsContact(txn, contactId2));
|
||||
// Delete the contact with the highest ID
|
||||
db.removeContact(txn, contactId2);
|
||||
assertFalse(db.containsContact(txn, contactId2));
|
||||
// Add another contact - a new ID should be created
|
||||
assertFalse(db.containsContact(txn, contactId3));
|
||||
assertEquals(contactId3, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId3, db.addContact(txn, secret));
|
||||
assertTrue(db.containsContact(txn, contactId3));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
@@ -242,7 +251,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and store a private message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addPrivateMessage(txn, privateMessage, contactId);
|
||||
|
||||
// Removing the contact should remove the message
|
||||
@@ -261,7 +270,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and store a private message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addPrivateMessage(txn, privateMessage, contactId);
|
||||
|
||||
// The message has no status yet, so it should not be sendable
|
||||
@@ -300,7 +309,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and store a private message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addPrivateMessage(txn, privateMessage, contactId);
|
||||
db.setStatus(txn, contactId, privateMessageId, Status.NEW);
|
||||
|
||||
@@ -328,7 +337,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -366,7 +375,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -408,7 +417,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.addGroupMessage(txn, message);
|
||||
@@ -447,7 +456,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.addGroupMessage(txn, message);
|
||||
@@ -482,7 +491,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -513,7 +522,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
db.addGroupMessage(txn, message);
|
||||
@@ -546,7 +555,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and some batches to ack
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addBatchToAck(txn, contactId, batchId);
|
||||
db.addBatchToAck(txn, contactId, batchId1);
|
||||
|
||||
@@ -573,7 +582,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and receive the same batch twice
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addBatchToAck(txn, contactId, batchId);
|
||||
db.addBatchToAck(txn, contactId, batchId);
|
||||
|
||||
@@ -599,7 +608,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.addGroupMessage(txn, message);
|
||||
|
||||
@@ -624,8 +633,8 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add two contacts, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
ContactId contactId1 = db.addContact(txn, transports, secret);
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
ContactId contactId1 = db.addContact(txn, secret);
|
||||
db.addSubscription(txn, group);
|
||||
db.addGroupMessage(txn, message);
|
||||
|
||||
@@ -647,7 +656,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -686,7 +695,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -731,12 +740,12 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
|
||||
// Add some outstanding batches, a few ms apart
|
||||
for(int i = 0; i < ids.length; i++) {
|
||||
db.addOutstandingBatch(txn, contactId, ids[i],
|
||||
Collections.<MessageId>emptySet());
|
||||
Collections.<MessageId>emptyList());
|
||||
Thread.sleep(5);
|
||||
}
|
||||
|
||||
@@ -771,12 +780,12 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
|
||||
// Add some outstanding batches, a few ms apart
|
||||
for(int i = 0; i < ids.length; i++) {
|
||||
db.addOutstandingBatch(txn, contactId, ids[i],
|
||||
Collections.<MessageId>emptySet());
|
||||
Collections.<MessageId>emptyList());
|
||||
Thread.sleep(5);
|
||||
}
|
||||
|
||||
@@ -991,43 +1000,55 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact with some transport properties
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.setTransports(txn, contactId, remoteTransports, 1);
|
||||
assertEquals(remoteProperties,
|
||||
db.getRemoteProperties(txn, transportId));
|
||||
|
||||
// Replace the transport properties
|
||||
TransportProperties properties1 =
|
||||
new TransportProperties(Collections.singletonMap("baz", "bam"));
|
||||
Map<TransportId, TransportProperties> transports1 =
|
||||
Collections.singletonMap(transportId, properties1);
|
||||
Transport remoteTransport1 =
|
||||
new Transport(transportId, remoteIndex, properties1);
|
||||
Collection<Transport> remoteTransports1 =
|
||||
Collections.singletonList(remoteTransport1);
|
||||
Map<ContactId, TransportProperties> remoteProperties1 =
|
||||
Collections.singletonMap(contactId, properties1);
|
||||
db.setTransports(txn, contactId, transports1, 1);
|
||||
db.setTransports(txn, contactId, remoteTransports1, 2);
|
||||
assertEquals(remoteProperties1,
|
||||
db.getRemoteProperties(txn, transportId));
|
||||
|
||||
// Remove the transport properties
|
||||
db.setTransports(txn, contactId,
|
||||
Collections.<TransportId, TransportProperties>emptyMap(), 2);
|
||||
db.setTransports(txn, contactId, Collections.<Transport>emptyList(), 3);
|
||||
assertEquals(Collections.emptyMap(),
|
||||
db.getRemoteProperties(txn, transportId));
|
||||
|
||||
// Set the local transport properties
|
||||
for(Entry<TransportId, TransportProperties> e : transports.entrySet()) {
|
||||
db.setLocalProperties(txn, e.getKey(), e.getValue());
|
||||
}
|
||||
assertEquals(transports, db.getLocalTransports(txn));
|
||||
|
||||
// Remove the local transport properties
|
||||
for(TransportId t : transports.keySet()) {
|
||||
db.setLocalProperties(txn, t, new TransportProperties());
|
||||
}
|
||||
assertEquals(Collections.emptyMap(), db.getLocalTransports(txn));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalTransports() throws Exception {
|
||||
Database<Connection> db = open(false);
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Allocate a transport index
|
||||
assertEquals(localIndex, db.addTransport(txn, transportId));
|
||||
|
||||
// Set the local transport properties
|
||||
db.setLocalProperties(txn, transportId, properties);
|
||||
assertEquals(Collections.singletonList(properties),
|
||||
db.getLocalTransports(txn));
|
||||
|
||||
// Remove the local transport properties - the transport itself will
|
||||
// not be removed
|
||||
db.setLocalProperties(txn, transportId, new TransportProperties());
|
||||
assertEquals(Collections.singletonList(Collections.emptyMap()),
|
||||
db.getLocalTransports(txn));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateTransportConfig() throws Exception {
|
||||
@@ -1039,6 +1060,9 @@ public class H2DatabaseTest extends TestCase {
|
||||
Database<Connection> db = open(false);
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Allocate a transport index
|
||||
assertEquals(localIndex, db.addTransport(txn, transportId));
|
||||
|
||||
// Set the transport config
|
||||
db.setConfig(txn, transportId, config);
|
||||
assertEquals(config, db.getConfig(txn, transportId));
|
||||
@@ -1049,8 +1073,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
|
||||
// Remove the transport config
|
||||
db.setConfig(txn, transportId, new TransportConfig());
|
||||
assertEquals(Collections.emptyMap(),
|
||||
db.getConfig(txn, transportId));
|
||||
assertEquals(Collections.emptyMap(), db.getConfig(txn, transportId));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
@@ -1062,27 +1085,32 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact with some transport properties
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.setTransports(txn, contactId, remoteTransports, 1);
|
||||
assertEquals(remoteProperties,
|
||||
db.getRemoteProperties(txn, transportId));
|
||||
|
||||
// Replace the transport properties using a timestamp of 2
|
||||
TransportProperties properties1 =
|
||||
new TransportProperties(Collections.singletonMap("baz", "bam"));
|
||||
Map<TransportId, TransportProperties> transports1 =
|
||||
Collections.singletonMap(transportId, properties1);
|
||||
Transport remoteTransport1 =
|
||||
new Transport(transportId, remoteIndex, properties1);
|
||||
Collection<Transport> remoteTransports1 =
|
||||
Collections.singletonList(remoteTransport1);
|
||||
Map<ContactId, TransportProperties> remoteProperties1 =
|
||||
Collections.singletonMap(contactId, properties1);
|
||||
db.setTransports(txn, contactId, transports1, 2);
|
||||
db.setTransports(txn, contactId, remoteTransports1, 2);
|
||||
assertEquals(remoteProperties1,
|
||||
db.getRemoteProperties(txn, transportId));
|
||||
|
||||
// Try to replace the transport properties using a timestamp of 1
|
||||
TransportProperties properties2 =
|
||||
new TransportProperties(Collections.singletonMap("quux", "etc"));
|
||||
Map<TransportId, TransportProperties> transports2 =
|
||||
Collections.singletonMap(transportId, properties2);
|
||||
db.setTransports(txn, contactId, transports2, 1);
|
||||
Transport remoteTransport2 =
|
||||
new Transport(transportId, remoteIndex, properties2);
|
||||
Collection<Transport> remoteTransports2 =
|
||||
Collections.singletonList(remoteTransport2);
|
||||
db.setTransports(txn, contactId, remoteTransports2, 1);
|
||||
|
||||
// The old properties should still be there
|
||||
assertEquals(remoteProperties1,
|
||||
@@ -1100,10 +1128,8 @@ public class H2DatabaseTest extends TestCase {
|
||||
Database<Connection> db = open(false);
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
|
||||
// Add some subscriptions
|
||||
// Add a contact with some subscriptions
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
assertEquals(Collections.singletonList(group),
|
||||
db.getSubscriptions(txn, contactId));
|
||||
@@ -1127,10 +1153,8 @@ public class H2DatabaseTest extends TestCase {
|
||||
Database<Connection> db = open(false);
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
|
||||
// Add some subscriptions
|
||||
// Add a contact with some subscriptions
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 2);
|
||||
assertEquals(Collections.singletonList(group),
|
||||
db.getSubscriptions(txn, contactId));
|
||||
@@ -1154,7 +1178,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and subscribe to a group
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
|
||||
@@ -1172,7 +1196,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
db.addGroupMessage(txn, message);
|
||||
@@ -1195,7 +1219,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
db.addGroupMessage(txn, message);
|
||||
@@ -1218,7 +1242,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
|
||||
// Add a contact, subscribe to a group and store a message -
|
||||
// the message is older than the contact's subscription
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
Map<Group, Long> subs = Collections.singletonMap(group, timestamp + 1);
|
||||
@@ -1242,7 +1266,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -1267,7 +1291,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and subscribe to a group
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -1286,7 +1310,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact with a subscription
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
|
||||
// There's no local subscription for the group
|
||||
@@ -1303,7 +1327,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.addGroupMessage(txn, message);
|
||||
db.setStatus(txn, contactId, messageId, Status.NEW);
|
||||
@@ -1322,7 +1346,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.addGroupMessage(txn, message);
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -1342,7 +1366,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -1364,7 +1388,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact, subscribe to a group and store a message
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
db.setVisibility(txn, groupId, Collections.singleton(contactId));
|
||||
db.setSubscriptions(txn, contactId, subscriptions, 1);
|
||||
@@ -1385,7 +1409,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and subscribe to a group
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
// The group should not be visible to the contact
|
||||
assertEquals(Collections.emptyList(), db.getVisibility(txn, groupId));
|
||||
@@ -1394,7 +1418,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
assertEquals(Collections.singletonList(contactId),
|
||||
db.getVisibility(txn, groupId));
|
||||
// Make the group invisible again
|
||||
db.setVisibility(txn, groupId, Collections.<ContactId>emptySet());
|
||||
db.setVisibility(txn, groupId, Collections.<ContactId>emptyList());
|
||||
assertEquals(Collections.emptyList(), db.getVisibility(txn, groupId));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
@@ -1408,10 +1432,10 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
// Get the connection window for a new transport
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
// Get the connection window for a new index
|
||||
ConnectionWindow w = db.getConnectionWindow(txn, contactId,
|
||||
transportId);
|
||||
remoteIndex);
|
||||
// The connection window should exist and be in the initial state
|
||||
assertNotNull(w);
|
||||
assertEquals(0L, w.getCentre());
|
||||
@@ -1427,19 +1451,19 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
// Get the connection window for a new transport
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
// Get the connection window for a new index
|
||||
ConnectionWindow w = db.getConnectionWindow(txn, contactId,
|
||||
transportId);
|
||||
remoteIndex);
|
||||
// The connection window should exist and be in the initial state
|
||||
assertNotNull(w);
|
||||
assertEquals(0L, w.getCentre());
|
||||
assertEquals(0, w.getBitmap());
|
||||
// Update the connection window and store it
|
||||
w.setSeen(5L);
|
||||
db.setConnectionWindow(txn, contactId, transportId, w);
|
||||
db.setConnectionWindow(txn, contactId, remoteIndex, w);
|
||||
// Check that the connection window was stored
|
||||
w = db.getConnectionWindow(txn, contactId, transportId);
|
||||
w = db.getConnectionWindow(txn, contactId, remoteIndex);
|
||||
assertNotNull(w);
|
||||
assertEquals(6L, w.getCentre());
|
||||
assertTrue(w.isSeen(5L));
|
||||
@@ -1527,7 +1551,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and subscribe to a group
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
|
||||
// A message with a private parent should return null
|
||||
@@ -1576,7 +1600,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
|
||||
// The subscription and transport timestamps should be initialised to 0
|
||||
assertEquals(0L, db.getSubscriptionsModified(txn, contactId));
|
||||
@@ -1606,7 +1630,7 @@ public class H2DatabaseTest extends TestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact and subscribe to a group
|
||||
assertEquals(contactId, db.addContact(txn, transports, secret));
|
||||
assertEquals(contactId, db.addContact(txn, secret));
|
||||
db.addSubscription(txn, group);
|
||||
|
||||
// Store a couple of messages
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package net.sf.briar.db;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sf.briar.api.protocol.Group;
|
||||
import net.sf.briar.api.protocol.GroupId;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
|
||||
public class TestGroup implements Group {
|
||||
|
||||
@@ -29,8 +26,4 @@ public class TestGroup implements Group {
|
||||
public byte[] getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public void writeTo(Writer w) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user