Merge branch '229-transport-client' into 'master'

Transport properties client. #229

This branch moves support for exchanging transport properties from the sync layer to the client layer.

Local properties are stored in an unshared group. When a contact is added, the latest local properties are copied into a group shared with the contact. Whenever the local properties are updated, they're copied into the groups shared with all contacts.

The transport update messages include a unique device ID that prevents collisions between local and remote messages, and will be used in future for multi-device support.

See merge request !80
This commit is contained in:
akwizgran
2016-01-28 15:05:00 +00:00
83 changed files with 898 additions and 2152 deletions

View File

@@ -13,7 +13,7 @@
<item>org.briarproject.lifecycle.LifecycleModule</item> <item>org.briarproject.lifecycle.LifecycleModule</item>
<item>org.briarproject.messaging.MessagingModule</item> <item>org.briarproject.messaging.MessagingModule</item>
<item>org.briarproject.plugins.AndroidPluginsModule</item> <item>org.briarproject.plugins.AndroidPluginsModule</item>
<item>org.briarproject.property.PropertyModule</item> <item>org.briarproject.properties.PropertiesModule</item>
<item>org.briarproject.sync.SyncModule</item> <item>org.briarproject.sync.SyncModule</item>
<item>org.briarproject.system.AndroidSystemModule</item> <item>org.briarproject.system.AndroidSystemModule</item>
<item>org.briarproject.transport.TransportModule</item> <item>org.briarproject.transport.TransportModule</item>

View File

@@ -11,7 +11,6 @@ import android.support.v4.app.TaskStackBuilder;
import org.briarproject.R; import org.briarproject.R;
import org.briarproject.android.contact.ConversationActivity; import org.briarproject.android.contact.ConversationActivity;
import org.briarproject.android.forum.ForumActivity; import org.briarproject.android.forum.ForumActivity;
import org.briarproject.api.Settings;
import org.briarproject.api.android.AndroidExecutor; import org.briarproject.api.android.AndroidExecutor;
import org.briarproject.api.android.AndroidNotificationManager; import org.briarproject.api.android.AndroidNotificationManager;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
@@ -24,6 +23,7 @@ import org.briarproject.api.event.SettingsUpdatedEvent;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.lifecycle.Service; import org.briarproject.api.lifecycle.Service;
import org.briarproject.api.messaging.MessagingManager; import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;

View File

@@ -29,13 +29,13 @@ import org.briarproject.android.util.HorizontalBorder;
import org.briarproject.android.util.LayoutUtils; import org.briarproject.android.util.LayoutUtils;
import org.briarproject.android.util.ListLoadingProgressBar; import org.briarproject.android.util.ListLoadingProgressBar;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.android.AndroidExecutor; import org.briarproject.api.android.AndroidExecutor;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.plugins.Plugin; import org.briarproject.api.plugins.Plugin;
import org.briarproject.api.plugins.PluginManager; import org.briarproject.api.plugins.PluginManager;
import org.briarproject.api.property.TransportPropertyManager; import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.io.File; import java.io.File;

View File

@@ -25,12 +25,12 @@ import org.briarproject.android.util.FixedVerticalSpace;
import org.briarproject.android.util.HorizontalBorder; import org.briarproject.android.util.HorizontalBorder;
import org.briarproject.android.util.LayoutUtils; import org.briarproject.android.util.LayoutUtils;
import org.briarproject.android.util.ListLoadingProgressBar; import org.briarproject.android.util.ListLoadingProgressBar;
import org.briarproject.api.Settings;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event; import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.SettingsUpdatedEvent; import org.briarproject.api.event.SettingsUpdatedEvent;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.settings.SettingsManager; import org.briarproject.api.settings.SettingsManager;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;

View File

@@ -1,15 +1,11 @@
package org.briarproject.android.invitation; package org.briarproject.android.invitation;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.widget.Toast; import android.widget.Toast;
import org.briarproject.R; import org.briarproject.R;
import org.briarproject.android.BriarActivity; import org.briarproject.android.BriarActivity;
import org.briarproject.android.util.AndroidUtils;
import org.briarproject.api.Settings;
import org.briarproject.api.TransportId;
import org.briarproject.api.android.ReferenceManager; import org.briarproject.api.android.ReferenceManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
@@ -60,8 +56,6 @@ implements InvitationListener {
// Fields that are accessed from background threads must be volatile // Fields that are accessed from background threads must be volatile
@Inject private volatile DatabaseComponent db; @Inject private volatile DatabaseComponent db;
@Inject private volatile IdentityManager identityManager; @Inject private volatile IdentityManager identityManager;
private volatile boolean bluetoothWasEnabled = false;
private volatile boolean leaveBluetoothEnabled = false;
@Override @Override
public void onCreate(Bundle state) { public void onCreate(Bundle state) {
@@ -69,9 +63,6 @@ implements InvitationListener {
if (state == null) { if (state == null) {
// This is a new activity // This is a new activity
setView(new ChooseIdentityView(this)); setView(new ChooseIdentityView(this));
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) bluetoothWasEnabled = adapter.isEnabled();
} else { } else {
// Restore the activity's state // Restore the activity's state
byte[] b = state.getByteArray("briar.LOCAL_AUTHOR_ID"); byte[] b = state.getByteArray("briar.LOCAL_AUTHOR_ID");
@@ -79,8 +70,6 @@ implements InvitationListener {
taskHandle = state.getLong("briar.TASK_HANDLE", -1); taskHandle = state.getLong("briar.TASK_HANDLE", -1);
task = referenceManager.getReference(taskHandle, task = referenceManager.getReference(taskHandle,
InvitationTask.class); InvitationTask.class);
bluetoothWasEnabled =
state.getBoolean("briar.BLUETOOTH_WAS_ENABLED");
if (task == null) { if (task == null) {
// No background task - we must be in an initial or final state // No background task - we must be in an initial or final state
@@ -162,26 +151,6 @@ implements InvitationListener {
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
view.populate(); view.populate();
loadBluetoothSetting();
}
private void loadBluetoothSetting() {
runOnDbThread(new Runnable() {
public void run() {
try {
long now = System.currentTimeMillis();
Settings s = db.getSettings("bt");
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading setting took " + duration + " ms");
leaveBluetoothEnabled = bluetoothWasEnabled
|| s.getBoolean("enable", false);
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
} }
@Override @Override
@@ -196,15 +165,12 @@ implements InvitationListener {
state.putBoolean("briar.FAILED", connectionFailed); state.putBoolean("briar.FAILED", connectionFailed);
state.putString("briar.CONTACT_NAME", contactName); state.putString("briar.CONTACT_NAME", contactName);
if (task != null) state.putLong("briar.TASK_HANDLE", taskHandle); if (task != null) state.putLong("briar.TASK_HANDLE", taskHandle);
state.putBoolean("briar.BLUETOOTH_WAS_ENABLED", bluetoothWasEnabled);
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
if (task != null) task.removeListener(this); if (task != null) task.removeListener(this);
if (isFinishing()) disableBluetooth();
} }
@Override @Override
@@ -295,7 +261,7 @@ implements InvitationListener {
setView(new InvitationCodeView(this, true)); setView(new InvitationCodeView(this, true));
task = invitationTaskFactory.createTask(localAuthorId, task = invitationTaskFactory.createTask(localAuthorId,
localInvitationCode, code, leaveBluetoothEnabled); localInvitationCode, code);
taskHandle = referenceManager.putReference(task, InvitationTask.class); taskHandle = referenceManager.putReference(task, InvitationTask.class);
task.addListener(AddContactActivity.this); task.addListener(AddContactActivity.this);
// Add a second listener so we can remove the first in onDestroy(), // Add a second listener so we can remove the first in onDestroy(),
@@ -329,15 +295,6 @@ implements InvitationListener {
} }
} }
public void disableBluetooth() {
if (!leaveBluetoothEnabled) {
if (LOG.isLoggable(INFO)) LOG.info("Turning off Bluetooth again");
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) AndroidUtils.setBluetooth(adapter, false);
}
}
public void connectionSucceeded() { public void connectionSucceeded() {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {

View File

@@ -1,23 +1,19 @@
package org.briarproject.android.invitation; package org.briarproject.android.invitation;
import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE;
import static android.bluetooth.BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION;
import static android.view.Gravity.CENTER;
import static org.briarproject.android.invitation.AddContactActivity.REQUEST_BLUETOOTH;
import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP;
import org.briarproject.R;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import org.briarproject.R;
import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE;
import static android.bluetooth.BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION;
import static org.briarproject.android.invitation.AddContactActivity.REQUEST_BLUETOOTH;
class ErrorView extends AddContactView implements OnClickListener { class ErrorView extends AddContactView implements OnClickListener {
private final int error; private final int error;
@@ -39,8 +35,6 @@ class ErrorView extends AddContactView implements OnClickListener {
removeAllViews(); removeAllViews();
Context ctx = getContext(); Context ctx = getContext();
container.disableBluetooth();
LayoutInflater inflater = (LayoutInflater) ctx.getSystemService LayoutInflater inflater = (LayoutInflater) ctx.getSystemService
(Context.LAYOUT_INFLATER_SERVICE); (Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.invitation_error, this); View view = inflater.inflate(R.layout.invitation_error, this);

View File

@@ -10,13 +10,13 @@ import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.android.AndroidExecutor; import org.briarproject.api.android.AndroidExecutor;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.util.LatchedReference; import org.briarproject.util.LatchedReference;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;

View File

@@ -13,9 +13,7 @@ import net.freehaven.tor.control.TorControlConnection;
import net.sourceforge.jsocks.socks.Socks5Proxy; import net.sourceforge.jsocks.socks.Socks5Proxy;
import net.sourceforge.jsocks.socks.SocksSocket; import net.sourceforge.jsocks.socks.SocksSocket;
import org.briarproject.api.Settings;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.event.Event; import org.briarproject.api.event.Event;
@@ -24,6 +22,8 @@ import org.briarproject.api.event.SettingsUpdatedEvent;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.system.LocationUtils; import org.briarproject.api.system.LocationUtils;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;

View File

@@ -0,0 +1,16 @@
package org.briarproject.api;
import java.util.Arrays;
/** Type-safe wrapper for a byte array that uniquely identifies a device. */
public class DeviceId extends UniqueId {
public DeviceId(byte[] id) {
super(id);
}
@Override
public boolean equals(Object o) {
return o instanceof DeviceId && Arrays.equals(id, ((DeviceId) o).id);
}
}

View File

@@ -3,7 +3,7 @@ package org.briarproject.api;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Map; import java.util.Map;
abstract class StringMap extends Hashtable<String, String> { public abstract class StringMap extends Hashtable<String, String> {
private static final long serialVersionUID = 2497176435908100448L; private static final long serialVersionUID = 2497176435908100448L;
@@ -26,4 +26,18 @@ abstract class StringMap extends Hashtable<String, String> {
public void putBoolean(String key, boolean value) { public void putBoolean(String key, boolean value) {
put(key, String.valueOf(value)); put(key, String.valueOf(value));
} }
public int getInt(String key, int defaultValue) {
String s = get(key);
if (s == null) return defaultValue;
try {
return Integer.valueOf(s);
} catch (NumberFormatException e) {
return defaultValue;
}
}
public void putInt(String key, int value) {
put(key, String.valueOf(value));
}
} }

View File

@@ -1,12 +1,13 @@
package org.briarproject.api; package org.briarproject.api;
import static org.briarproject.api.TransportPropertyConstants.MAX_TRANSPORT_ID_LENGTH;
/** /**
* Type-safe wrapper for a string that uniquely identifies a transport plugin. * Type-safe wrapper for a string that uniquely identifies a transport plugin.
*/ */
public class TransportId { public class TransportId {
/** The maximum length of transport identifier in UTF-8 bytes. */
public static int MAX_TRANSPORT_ID_LENGTH = 10;
private final String id; private final String id;
public TransportId(String id) { public TransportId(String id) {
@@ -21,8 +22,7 @@ public class TransportId {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o instanceof TransportId) return id.equals(((TransportId) o).id); return o instanceof TransportId && id.equals(((TransportId) o).id);
return false;
} }
@Override @Override

View File

@@ -1,13 +1,13 @@
package org.briarproject.api.db; package org.briarproject.api.db;
import org.briarproject.api.Settings; import org.briarproject.api.DeviceId;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.sync.Ack; import org.briarproject.api.sync.Ack;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
@@ -19,8 +19,6 @@ import org.briarproject.api.sync.Offer;
import org.briarproject.api.sync.Request; import org.briarproject.api.sync.Request;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.api.transport.TransportKeys; import org.briarproject.api.transport.TransportKeys;
import java.io.IOException; import java.io.IOException;
@@ -34,7 +32,7 @@ import java.util.Map;
public interface DatabaseComponent { public interface DatabaseComponent {
/** Opens the database and returns true if the database already existed. */ /** Opens the database and returns true if the database already existed. */
boolean open() throws DbException, IOException; boolean open() throws DbException;
/** Waits for any open transactions to finish and closes the database. */ /** Waits for any open transactions to finish and closes the database. */
void close() throws DbException, IOException; void close() throws DbException, IOException;
@@ -125,21 +123,6 @@ public interface DatabaseComponent {
SubscriptionUpdate generateSubscriptionUpdate(ContactId c, int maxLatency) SubscriptionUpdate generateSubscriptionUpdate(ContactId c, int maxLatency)
throws DbException; throws DbException;
/**
* Returns a batch of transport acks for the given contact, or null if no
* transport acks are due.
*/
Collection<TransportAck> generateTransportAcks(ContactId c)
throws DbException;
/**
* Returns a batch of transport updates for the given contact, for
* transmission over a transport with the given latency. Returns null if no
* updates are due.
*/
Collection<TransportUpdate> generateTransportUpdates(ContactId c,
int maxLatency) throws DbException;
/** /**
* Returns all groups belonging to the given client to which the user could * Returns all groups belonging to the given client to which the user could
* subscribe. * subscribe.
@@ -155,6 +138,9 @@ public interface DatabaseComponent {
/** Returns all contacts associated with the given local pseudonym. */ /** Returns all contacts associated with the given local pseudonym. */
Collection<ContactId> getContacts(AuthorId a) throws DbException; Collection<ContactId> getContacts(AuthorId a) throws DbException;
/** Returns the unique ID for this device. */
DeviceId getDeviceId() throws DbException;
/** Returns the group with the given ID, if the user subscribes to it. */ /** Returns the group with the given ID, if the user subscribes to it. */
Group getGroup(GroupId g) throws DbException; Group getGroup(GroupId g) throws DbException;
@@ -173,13 +159,6 @@ public interface DatabaseComponent {
/** Returns all local pseudonyms. */ /** Returns all local pseudonyms. */
Collection<LocalAuthor> getLocalAuthors() throws DbException; Collection<LocalAuthor> getLocalAuthors() throws DbException;
/** Returns the local transport properties for all transports. */
Map<TransportId, TransportProperties> getLocalProperties()
throws DbException;
/** Returns the local transport properties for the given transport. */
TransportProperties getLocalProperties(TransportId t) throws DbException;
/** /**
* Returns the IDs of any messages that need to be validated by the given * Returns the IDs of any messages that need to be validated by the given
* client. * client.
@@ -210,10 +189,6 @@ public interface DatabaseComponent {
MessageStatus getMessageStatus(ContactId c, MessageId m) MessageStatus getMessageStatus(ContactId c, MessageId m)
throws DbException; throws DbException;
/** Returns all remote transport properties for the given transport. */
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
throws DbException;
/** Returns all settings in the given namespace. */ /** Returns all settings in the given namespace. */
Settings getSettings(String namespace) throws DbException; Settings getSettings(String namespace) throws DbException;
@@ -243,13 +218,6 @@ public interface DatabaseComponent {
*/ */
void mergeGroupMetadata(GroupId g, Metadata meta) throws DbException; void mergeGroupMetadata(GroupId g, Metadata meta) throws DbException;
/**
* Merges the given properties with the existing local properties for the
* given transport.
*/
void mergeLocalProperties(TransportId t, TransportProperties p)
throws DbException;
/** /**
* Merges the given metadata with the existing metadata for the given * Merges the given metadata with the existing metadata for the given
* message. * message.
@@ -282,13 +250,6 @@ public interface DatabaseComponent {
void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate u) void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate u)
throws DbException; throws DbException;
/** Processes a transport ack from the given contact. */
void receiveTransportAck(ContactId c, TransportAck a) throws DbException;
/** Processes a transport update from the given contact. */
void receiveTransportUpdate(ContactId c, TransportUpdate u)
throws DbException;
/** Removes a contact (and all associated state) from the database. */ /** Removes a contact (and all associated state) from the database. */
void removeContact(ContactId c) throws DbException; void removeContact(ContactId c) throws DbException;
@@ -320,13 +281,6 @@ public interface DatabaseComponent {
void setMessageValidity(Message m, ClientId c, boolean valid) void setMessageValidity(Message m, ClientId c, boolean valid)
throws DbException; throws DbException;
/**
* Sets the remote transport properties for the given contact, replacing
* any existing properties.
*/
void setRemoteProperties(ContactId c,
Map<TransportId, TransportProperties> p) throws DbException;
/** /**
* Sets the reordering window for the given contact and transport in the * Sets the reordering window for the given contact and transport in the
* given rotation period. * given rotation period.

View File

@@ -1,9 +0,0 @@
package org.briarproject.api.event;
/**
* An event that is broadcast when the local transport properties are
* updated.
*/
public class LocalTransportsUpdatedEvent extends Event {
}

View File

@@ -1,28 +0,0 @@
package org.briarproject.api.event;
import org.briarproject.api.TransportId;
import org.briarproject.api.contact.ContactId;
/**
* An event that is broadcast when a contact's remote transport properties
* are updated.
*/
public class RemoteTransportsUpdatedEvent extends Event {
private final ContactId contactId;
private final TransportId transportId;
public RemoteTransportsUpdatedEvent(ContactId contactId,
TransportId transportId) {
this.contactId = contactId;
this.transportId = transportId;
}
public ContactId getContactId() {
return contactId;
}
public TransportId getTransportId() {
return transportId;
}
}

View File

@@ -7,5 +7,5 @@ public interface InvitationTaskFactory {
/** Creates a task using the given pseudonym and invitation codes. */ /** Creates a task using the given pseudonym and invitation codes. */
InvitationTask createTask(AuthorId localAuthorId, int localCode, InvitationTask createTask(AuthorId localAuthorId, int localCode,
int remoteCode, boolean reuseConnection); int remoteCode);
} }

View File

@@ -1,8 +1,8 @@
package org.briarproject.api.plugins; package org.briarproject.api.plugins;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.Settings; import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.settings.Settings;
import java.util.Map; import java.util.Map;

View File

@@ -1,4 +1,6 @@
package org.briarproject.api; package org.briarproject.api.properties;
import org.briarproject.api.StringMap;
import java.util.Map; import java.util.Map;

View File

@@ -1,13 +1,7 @@
package org.briarproject.api; package org.briarproject.api.properties;
public interface TransportPropertyConstants { public interface TransportPropertyConstants {
/**
* The maximum length of a string that uniquely identifies a transport
* plugin.
*/
int MAX_TRANSPORT_ID_LENGTH = 10;
/** The maximum number of properties per transport. */ /** The maximum number of properties per transport. */
int MAX_PROPERTIES_PER_TRANSPORT = 100; int MAX_PROPERTIES_PER_TRANSPORT = 100;

View File

@@ -1,7 +1,6 @@
package org.briarproject.api.property; package org.briarproject.api.properties;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
@@ -26,11 +25,4 @@ public interface TransportPropertyManager {
*/ */
void mergeLocalProperties(TransportId t, TransportProperties p) void mergeLocalProperties(TransportId t, TransportProperties p)
throws DbException; throws DbException;
/**
* Sets the remote transport properties for the given contact, replacing
* any existing properties.
*/
void setRemoteProperties(ContactId c,
Map<TransportId, TransportProperties> p) throws DbException;
} }

View File

@@ -1,4 +1,6 @@
package org.briarproject.api; package org.briarproject.api.settings;
import org.briarproject.api.StringMap;
public class Settings extends StringMap { public class Settings extends StringMap {

View File

@@ -1,6 +1,5 @@
package org.briarproject.api.settings; package org.briarproject.api.settings;
import org.briarproject.api.Settings;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
public interface SettingsManager { public interface SettingsManager {

View File

@@ -23,10 +23,4 @@ public interface PacketReader {
boolean hasSubscriptionUpdate() throws IOException; boolean hasSubscriptionUpdate() throws IOException;
SubscriptionUpdate readSubscriptionUpdate() throws IOException; SubscriptionUpdate readSubscriptionUpdate() throws IOException;
boolean hasTransportAck() throws IOException;
TransportAck readTransportAck() throws IOException;
boolean hasTransportUpdate() throws IOException;
TransportUpdate readTransportUpdate() throws IOException;
} }

View File

@@ -9,6 +9,4 @@ public interface PacketTypes {
byte REQUEST = 3; byte REQUEST = 3;
byte SUBSCRIPTION_ACK = 6; byte SUBSCRIPTION_ACK = 6;
byte SUBSCRIPTION_UPDATE = 7; byte SUBSCRIPTION_UPDATE = 7;
byte TRANSPORT_ACK = 8;
byte TRANSPORT_UPDATE = 9;
} }

View File

@@ -22,9 +22,5 @@ public interface PacketWriter {
void writeSubscriptionUpdate(SubscriptionUpdate u) throws IOException; void writeSubscriptionUpdate(SubscriptionUpdate u) throws IOException;
void writeTransportAck(TransportAck a) throws IOException;
void writeTransportUpdate(TransportUpdate u) throws IOException;
void flush() throws IOException; void flush() throws IOException;
} }

View File

@@ -1,25 +0,0 @@
package org.briarproject.api.sync;
import org.briarproject.api.TransportId;
/** A packet acknowledging a {@link TransportUpdate}. */
public class TransportAck {
private final TransportId id;
private final long version;
public TransportAck(TransportId id, long version) {
this.id = id;
this.version = version;
}
/** Returns the identifier of the updated transport. */
public TransportId getId() {
return id;
}
/** Returns the version number of the acknowledged update. */
public long getVersion() {
return version;
}
}

View File

@@ -1,36 +0,0 @@
package org.briarproject.api.sync;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
/**
* A packet updating the recipient's view of the sender's transport properties.
*/
public class TransportUpdate {
private final TransportId id;
private final TransportProperties properties;
private final long version;
public TransportUpdate(TransportId id, TransportProperties properties,
long version) {
this.id = id;
this.properties = properties;
this.version = version;
}
/** Returns the identifier of the updated transport. */
public TransportId getId() {
return id;
}
/** Returns the transport's updated properties. */
public TransportProperties getProperties() {
return properties;
}
/** Returns the update's version number. */
public long getVersion() {
return version;
}
}

View File

@@ -4,8 +4,6 @@ import org.briarproject.api.TransportId;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
import java.util.Collection;
/** /**
* Responsible for managing transport keys and recognising the pseudo-random * Responsible for managing transport keys and recognising the pseudo-random
* tags of incoming streams. * tags of incoming streams.
@@ -18,8 +16,8 @@ public interface KeyManager {
* {@link StreamContext StreamContexts} for the contact can be created * {@link StreamContext StreamContexts} for the contact can be created
* after this method has returned. * after this method has returned.
*/ */
void addContact(ContactId c, Collection<TransportId> transports, void addContact(ContactId c, SecretKey master, long timestamp,
SecretKey master, long timestamp, boolean alice); boolean alice);
/** /**
* Returns a {@link StreamContext} for sending a stream to the given * Returns a {@link StreamContext} for sending a stream to the given

View File

@@ -10,6 +10,7 @@ import org.briarproject.api.crypto.StreamDecrypterFactory;
import org.briarproject.api.crypto.StreamEncrypterFactory; import org.briarproject.api.crypto.StreamEncrypterFactory;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import java.security.SecureRandom;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@@ -57,4 +58,9 @@ public class CryptoModule extends AbstractModule {
lifecycleManager.registerForShutdown(cryptoExecutor); lifecycleManager.registerForShutdown(cryptoExecutor);
return cryptoExecutor; return cryptoExecutor;
} }
@Provides
SecureRandom getSecureRandom(CryptoComponent crypto) {
return crypto.getSecureRandom();
}
} }

View File

@@ -1,8 +1,7 @@
package org.briarproject.db; package org.briarproject.db;
import org.briarproject.api.Settings; import org.briarproject.api.DeviceId;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
@@ -11,6 +10,7 @@ import org.briarproject.api.db.StorageStatus;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
@@ -19,8 +19,6 @@ import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.MessageStatus; import org.briarproject.api.sync.MessageStatus;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.api.transport.TransportKeys; import org.briarproject.api.transport.TransportKeys;
import java.io.IOException; import java.io.IOException;
@@ -43,7 +41,7 @@ interface Database<T> {
* <p> * <p>
* Locking: write. * Locking: write.
*/ */
boolean open() throws DbException, IOException; boolean open() throws DbException;
/** /**
* Prevents new transactions from starting, waits for all current * Prevents new transactions from starting, waits for all current
@@ -259,6 +257,13 @@ interface Database<T> {
*/ */
Collection<ContactId> getContacts(T txn, AuthorId a) throws DbException; Collection<ContactId> getContacts(T txn, AuthorId a) throws DbException;
/**
* Returns the unique ID for this device.
* <p>
* Locking: read.
*/
DeviceId getDeviceId(T txn) throws DbException;
/** /**
* Returns the amount of free storage space available to the database, in * Returns the amount of free storage space available to the database, in
* bytes. This is based on the minimum of the space available on the device * bytes. This is based on the minimum of the space available on the device
@@ -302,22 +307,6 @@ interface Database<T> {
*/ */
Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException; Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException;
/**
* Returns the local transport properties for all transports.
* <p>
* Locking: read.
*/
Map<TransportId, TransportProperties> getLocalProperties(T txn)
throws DbException;
/**
* Returns the local transport properties for the given transport.
* <p>
* Locking: read.
*/
TransportProperties getLocalProperties(T txn, TransportId t)
throws DbException;
/** /**
* Returns the metadata for all messages in the given group. * Returns the metadata for all messages in the given group.
* <p> * <p>
@@ -403,14 +392,6 @@ interface Database<T> {
*/ */
byte[] getRawMessage(T txn, MessageId m) throws DbException; byte[] getRawMessage(T txn, MessageId m) throws DbException;
/**
* Returns all remote properties for the given transport.
* <p>
* Locking: read.
*/
Map<ContactId, TransportProperties> getRemoteProperties(T txn,
TransportId t) throws DbException;
/** /**
* Returns the IDs of some messages that are eligible to be sent to the * Returns the IDs of some messages that are eligible to be sent to the
* given contact and have been requested by the contact, up to the given * given contact and have been requested by the contact, up to the given
@@ -452,15 +433,6 @@ interface Database<T> {
SubscriptionUpdate getSubscriptionUpdate(T txn, ContactId c, SubscriptionUpdate getSubscriptionUpdate(T txn, ContactId c,
int maxLatency) throws DbException; int maxLatency) throws DbException;
/**
* Returns a collection of transport acks for the given contact, or null if
* no acks are due.
* <p>
* Locking: write.
*/
Collection<TransportAck> getTransportAcks(T txn, ContactId c)
throws DbException;
/** /**
* Returns all transport keys for the given transport. * Returns all transport keys for the given transport.
* <p> * <p>
@@ -476,16 +448,6 @@ interface Database<T> {
*/ */
Map<TransportId, Integer> getTransportLatencies(T txn) throws DbException; Map<TransportId, Integer> getTransportLatencies(T txn) throws DbException;
/**
* Returns a collection of transport updates for the given contact and
* updates their expiry times using the given latency, or returns null if
* no updates are due.
* <p>
* Locking: write.
*/
Collection<TransportUpdate> getTransportUpdates(T txn, ContactId c,
int maxLatency) throws DbException;
/** /**
* Returns the IDs of all contacts to which the given group is visible. * Returns the IDs of all contacts to which the given group is visible.
* <p> * <p>
@@ -529,15 +491,6 @@ interface Database<T> {
void mergeGroupMetadata(T txn, GroupId g, Metadata meta) void mergeGroupMetadata(T txn, GroupId g, Metadata meta)
throws DbException; throws DbException;
/**
* Merges the given properties with the existing local properties for the
* given transport.
* <p>
* Locking: write.
*/
void mergeLocalProperties(T txn, TransportId t, TransportProperties p)
throws DbException;
/* /*
* Merges the given metadata with the existing metadata for the given * Merges the given metadata with the existing metadata for the given
* message. * message.
@@ -689,26 +642,6 @@ interface Database<T> {
boolean setGroups(T txn, ContactId c, Collection<Group> groups, boolean setGroups(T txn, ContactId c, Collection<Group> groups,
long version) throws DbException; long version) throws DbException;
/**
* Sets the remote transport properties for the given contact, replacing
* any existing properties.
* <p>
* Locking: write.
*/
void setRemoteProperties(T txn, ContactId c,
Map<TransportId, TransportProperties> p) throws DbException;
/**
* Updates the remote transport properties for the given contact and the
* given transport, replacing any existing properties, and returns true,
* unless an update with an equal or higher version number has already been
* received from the contact.
* <p>
* Locking: write.
*/
boolean setRemoteProperties(T txn, ContactId c, TransportId t,
TransportProperties p, long version) throws DbException;
/** /**
* Records a subscription ack from the given contact for the given version, * Records a subscription ack from the given contact for the given version,
* unless the contact has already acked an equal or higher version. * unless the contact has already acked an equal or higher version.
@@ -718,15 +651,6 @@ interface Database<T> {
void setSubscriptionUpdateAcked(T txn, ContactId c, long version) void setSubscriptionUpdateAcked(T txn, ContactId c, long version)
throws DbException; throws DbException;
/**
* Records a transport ack from the give contact for the given version,
* unless the contact has already acked an equal or higher version.
* <p>
* Locking: write.
*/
void setTransportUpdateAcked(T txn, ContactId c, TransportId t,
long version) throws DbException;
/** /**
* Makes a group visible or invisible to future contacts by default. * Makes a group visible or invisible to future contacts by default.
* <p> * <p>

View File

@@ -1,8 +1,7 @@
package org.briarproject.db; package org.briarproject.db;
import org.briarproject.api.Settings; import org.briarproject.api.DeviceId;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.ContactExistsException; import org.briarproject.api.db.ContactExistsException;
@@ -19,7 +18,6 @@ import org.briarproject.api.db.NoSuchTransportException;
import org.briarproject.api.db.StorageStatus; import org.briarproject.api.db.StorageStatus;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent; import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
import org.briarproject.api.event.LocalTransportsUpdatedEvent;
import org.briarproject.api.event.MessageAddedEvent; import org.briarproject.api.event.MessageAddedEvent;
import org.briarproject.api.event.MessageRequestedEvent; import org.briarproject.api.event.MessageRequestedEvent;
import org.briarproject.api.event.MessageToAckEvent; import org.briarproject.api.event.MessageToAckEvent;
@@ -28,7 +26,6 @@ import org.briarproject.api.event.MessageValidatedEvent;
import org.briarproject.api.event.MessagesAckedEvent; import org.briarproject.api.event.MessagesAckedEvent;
import org.briarproject.api.event.MessagesSentEvent; import org.briarproject.api.event.MessagesSentEvent;
import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent; import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent;
import org.briarproject.api.event.RemoteTransportsUpdatedEvent;
import org.briarproject.api.event.SettingsUpdatedEvent; import org.briarproject.api.event.SettingsUpdatedEvent;
import org.briarproject.api.event.SubscriptionAddedEvent; import org.briarproject.api.event.SubscriptionAddedEvent;
import org.briarproject.api.event.SubscriptionRemovedEvent; import org.briarproject.api.event.SubscriptionRemovedEvent;
@@ -38,6 +35,7 @@ import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.lifecycle.ShutdownManager; import org.briarproject.api.lifecycle.ShutdownManager;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.sync.Ack; import org.briarproject.api.sync.Ack;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
@@ -49,8 +47,6 @@ import org.briarproject.api.sync.Offer;
import org.briarproject.api.sync.Request; import org.briarproject.api.sync.Request;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.api.transport.TransportKeys; import org.briarproject.api.transport.TransportKeys;
import java.io.IOException; import java.io.IOException;
@@ -99,7 +95,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
this.shutdown = shutdown; this.shutdown = shutdown;
} }
public boolean open() throws DbException, IOException { public boolean open() throws DbException {
Runnable shutdownHook = new Runnable() { Runnable shutdownHook = new Runnable() {
public void run() { public void run() {
lock.writeLock().lock(); lock.writeLock().lock();
@@ -475,47 +471,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
} }
public Collection<TransportAck> generateTransportAcks(ContactId c)
throws DbException {
lock.writeLock().lock();
try {
T txn = db.startTransaction();
try {
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<TransportAck> acks = db.getTransportAcks(txn, c);
db.commitTransaction(txn);
return acks;
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.writeLock().unlock();
}
}
public Collection<TransportUpdate> generateTransportUpdates(ContactId c,
int maxLatency) throws DbException {
lock.writeLock().lock();
try {
T txn = db.startTransaction();
try {
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<TransportUpdate> updates =
db.getTransportUpdates(txn, c, maxLatency);
db.commitTransaction(txn);
return updates;
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.writeLock().unlock();
}
}
public Collection<Group> getAvailableGroups(ClientId c) throws DbException { public Collection<Group> getAvailableGroups(ClientId c) throws DbException {
lock.readLock().lock(); lock.readLock().lock();
try { try {
@@ -588,6 +543,23 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
} }
public DeviceId getDeviceId() throws DbException {
lock.readLock().lock();
try {
T txn = db.startTransaction();
try {
DeviceId id = db.getDeviceId(txn);
db.commitTransaction(txn);
return id;
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.readLock().unlock();
}
}
public Group getGroup(GroupId g) throws DbException { public Group getGroup(GroupId g) throws DbException {
lock.readLock().lock(); lock.readLock().lock();
try { try {
@@ -679,45 +651,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
} }
public Map<TransportId, TransportProperties> getLocalProperties()
throws DbException {
lock.readLock().lock();
try {
T txn = db.startTransaction();
try {
Map<TransportId, TransportProperties> properties =
db.getLocalProperties(txn);
db.commitTransaction(txn);
return properties;
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.readLock().unlock();
}
}
public TransportProperties getLocalProperties(TransportId t)
throws DbException {
lock.readLock().lock();
try {
T txn = db.startTransaction();
try {
if (!db.containsTransport(txn, t))
throw new NoSuchTransportException();
TransportProperties properties = db.getLocalProperties(txn, t);
db.commitTransaction(txn);
return properties;
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.readLock().unlock();
}
}
public Collection<MessageId> getMessagesToValidate(ClientId c) public Collection<MessageId> getMessagesToValidate(ClientId c)
throws DbException { throws DbException {
lock.readLock().lock(); lock.readLock().lock();
@@ -840,25 +773,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
} }
public Map<ContactId, TransportProperties> getRemoteProperties(
TransportId t) throws DbException {
lock.readLock().lock();
try {
T txn = db.startTransaction();
try {
Map<ContactId, TransportProperties> properties =
db.getRemoteProperties(txn, t);
db.commitTransaction(txn);
return properties;
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.readLock().unlock();
}
}
public Settings getSettings(String namespace) throws DbException { public Settings getSettings(String namespace) throws DbException {
lock.readLock().lock(); lock.readLock().lock();
try { try {
@@ -992,30 +906,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
} }
public void mergeLocalProperties(TransportId t, TransportProperties p)
throws DbException {
boolean changed = false;
lock.writeLock().lock();
try {
T txn = db.startTransaction();
try {
if (!db.containsTransport(txn, t))
throw new NoSuchTransportException();
if (!p.equals(db.getLocalProperties(txn, t))) {
db.mergeLocalProperties(txn, t, p);
changed = true;
}
db.commitTransaction(txn);
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.writeLock().unlock();
}
if (changed) eventBus.broadcast(new LocalTransportsUpdatedEvent());
}
public void mergeMessageMetadata(MessageId m, Metadata meta) public void mergeMessageMetadata(MessageId m, Metadata meta)
throws DbException { throws DbException {
lock.writeLock().lock(); lock.writeLock().lock();
@@ -1208,52 +1098,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
if (updated) eventBus.broadcast(new RemoteSubscriptionsUpdatedEvent(c)); if (updated) eventBus.broadcast(new RemoteSubscriptionsUpdatedEvent(c));
} }
public void receiveTransportAck(ContactId c, TransportAck a)
throws DbException {
lock.writeLock().lock();
try {
T txn = db.startTransaction();
try {
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
if (!db.containsTransport(txn, a.getId()))
throw new NoSuchTransportException();
db.setTransportUpdateAcked(txn, c, a.getId(), a.getVersion());
db.commitTransaction(txn);
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.writeLock().unlock();
}
}
public void receiveTransportUpdate(ContactId c, TransportUpdate u)
throws DbException {
boolean updated;
lock.writeLock().lock();
try {
T txn = db.startTransaction();
try {
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
TransportId t = u.getId();
TransportProperties p = u.getProperties();
long version = u.getVersion();
updated = db.setRemoteProperties(txn, c, t, p, version);
db.commitTransaction(txn);
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.writeLock().unlock();
}
if (updated)
eventBus.broadcast(new RemoteTransportsUpdatedEvent(c, u.getId()));
}
public void removeContact(ContactId c) throws DbException { public void removeContact(ContactId c) throws DbException {
lock.writeLock().lock(); lock.writeLock().lock();
try { try {
@@ -1390,25 +1234,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
eventBus.broadcast(new MessageValidatedEvent(m, c, false, valid)); eventBus.broadcast(new MessageValidatedEvent(m, c, false, valid));
} }
public void setRemoteProperties(ContactId c,
Map<TransportId, TransportProperties> p) throws DbException {
lock.writeLock().lock();
try {
T txn = db.startTransaction();
try {
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
db.setRemoteProperties(txn, c, p);
db.commitTransaction(txn);
} catch (DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
lock.writeLock().unlock();
}
}
public void setReorderingWindow(ContactId c, TransportId t, public void setReorderingWindow(ContactId c, TransportId t,
long rotationPeriod, long base, byte[] bitmap) throws DbException { long rotationPeriod, long base, byte[] bitmap) throws DbException {
lock.writeLock().lock(); lock.writeLock().lock();

View File

@@ -1,5 +1,7 @@
package org.briarproject.db; package org.briarproject.db;
import org.briarproject.api.settings.Settings;
interface DatabaseConstants { interface DatabaseConstants {
/** /**
@@ -8,4 +10,34 @@ interface DatabaseConstants {
* limit is reached, additional offers will not be stored. * limit is reached, additional offers will not be stored.
*/ */
int MAX_OFFERED_MESSAGES = 1000; int MAX_OFFERED_MESSAGES = 1000;
/**
* The namespace of the {@link Settings Settings}
* where the database schema version is stored.
*/
String DB_SETTINGS_NAMESPACE = "db";
/**
* The {@link Settings Settings} key under which the
* database schema version is stored.
*/
String SCHEMA_VERSION_KEY = "schemaVersion";
/**
* The {@link Settings Settings} key under which the
* minimum supported database schema version is stored.
*/
String MIN_SCHEMA_VERSION_KEY = "minSchemaVersion";
/**
* The namespace of the {@link Settings Settings}
* where the unique device ID is stored.
*/
String DEVICE_SETTINGS_NAMESPACE = "device";
/**
* The {@link Settings Settings} key under which the
* unique device ID is stored.
*/
String DEVICE_ID_KEY = "deviceId";
} }

View File

@@ -9,8 +9,9 @@ import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.lifecycle.ShutdownManager; import org.briarproject.api.lifecycle.ShutdownManager;
import org.briarproject.system.SystemClock; import org.briarproject.api.system.Clock;
import java.security.SecureRandom;
import java.sql.Connection; import java.sql.Connection;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -39,13 +40,12 @@ public class DatabaseModule extends AbstractModule {
} }
@Override @Override
protected void configure() { protected void configure() {}
// Nothing to bind
}
@Provides @Singleton @Provides @Singleton
Database<Connection> getDatabase(DatabaseConfig config) { Database<Connection> getDatabase(DatabaseConfig config,
return new H2Database(config, new SystemClock()); SecureRandom random, Clock clock) {
return new H2Database(config, random, clock);
} }
@Provides @Singleton @Provides @Singleton

View File

@@ -6,11 +6,10 @@ import org.briarproject.api.system.Clock;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.security.SecureRandom;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; import java.util.Properties;
import javax.inject.Inject; import javax.inject.Inject;
@@ -18,7 +17,7 @@ import javax.inject.Inject;
/** Contains all the H2-specific code for the database. */ /** Contains all the H2-specific code for the database. */
class H2Database extends JdbcDatabase { class H2Database extends JdbcDatabase {
private static final String HASH_TYPE = "BINARY(48)"; private static final String HASH_TYPE = "BINARY(32)";
private static final String BINARY_TYPE = "BINARY"; private static final String BINARY_TYPE = "BINARY";
private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT"; private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
private static final String SECRET_TYPE = "BINARY(32)"; private static final String SECRET_TYPE = "BINARY(32)";
@@ -27,16 +26,16 @@ class H2Database extends JdbcDatabase {
private final String url; private final String url;
@Inject @Inject
H2Database(DatabaseConfig config, Clock clock) { H2Database(DatabaseConfig config, SecureRandom random, Clock clock) {
super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, clock); super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, random, clock);
this.config = config; this.config = config;
String path = new File(config.getDatabaseDirectory(), "db").getAbsolutePath(); File dir = config.getDatabaseDirectory();
// FIXME: Remove WRITE_DELAY=0 after implementing BTPv2? String path = new File(dir, "db").getAbsolutePath();
url = "jdbc:h2:split:" + path + ";CIPHER=AES;MULTI_THREADED=1" url = "jdbc:h2:split:" + path + ";CIPHER=AES;MULTI_THREADED=1"
+ ";WRITE_DELAY=0;DB_CLOSE_ON_EXIT=false"; + ";WRITE_DELAY=0;DB_CLOSE_ON_EXIT=false";
} }
public boolean open() throws DbException, IOException { public boolean open() throws DbException {
boolean reopen = config.databaseExists(); boolean reopen = config.databaseExists();
if (!reopen) config.getDatabaseDirectory().mkdirs(); if (!reopen) config.getDatabaseDirectory().mkdirs();
super.open("org.h2.Driver", reopen); super.open("org.h2.Driver", reopen);
@@ -83,10 +82,4 @@ class H2Database extends JdbcDatabase {
props.put("password", StringUtils.toHexString(key) + " password"); props.put("password", StringUtils.toHexString(key) + " password");
return DriverManager.getConnection(url, props); return DriverManager.getConnection(url, props);
} }
@Override
protected void flushBuffersToDisk(Statement s) throws SQLException {
// FIXME: Remove this after implementing BTPv2?
s.execute("CHECKPOINT SYNC");
}
} }

View File

@@ -1,8 +1,8 @@
package org.briarproject.db; package org.briarproject.db;
import org.briarproject.api.Settings; import org.briarproject.api.DeviceId;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties; import org.briarproject.api.UniqueId;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
@@ -13,6 +13,7 @@ import org.briarproject.api.db.StorageStatus;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
@@ -21,14 +22,13 @@ import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.MessageStatus; import org.briarproject.api.sync.MessageStatus;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.IncomingKeys; import org.briarproject.api.transport.IncomingKeys;
import org.briarproject.api.transport.OutgoingKeys; import org.briarproject.api.transport.OutgoingKeys;
import org.briarproject.api.transport.TransportKeys; import org.briarproject.api.transport.TransportKeys;
import org.briarproject.util.StringUtils;
import java.io.IOException; import java.security.SecureRandom;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
@@ -57,6 +57,11 @@ import static org.briarproject.api.sync.SyncConstants.MAX_SUBSCRIPTIONS;
import static org.briarproject.api.sync.ValidationManager.Status.INVALID; import static org.briarproject.api.sync.ValidationManager.Status.INVALID;
import static org.briarproject.api.sync.ValidationManager.Status.UNKNOWN; import static org.briarproject.api.sync.ValidationManager.Status.UNKNOWN;
import static org.briarproject.api.sync.ValidationManager.Status.VALID; import static org.briarproject.api.sync.ValidationManager.Status.VALID;
import static org.briarproject.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
import static org.briarproject.db.DatabaseConstants.DEVICE_ID_KEY;
import static org.briarproject.db.DatabaseConstants.DEVICE_SETTINGS_NAMESPACE;
import static org.briarproject.db.DatabaseConstants.MIN_SCHEMA_VERSION_KEY;
import static org.briarproject.db.DatabaseConstants.SCHEMA_VERSION_KEY;
import static org.briarproject.db.ExponentialBackoff.calculateExpiry; import static org.briarproject.db.ExponentialBackoff.calculateExpiry;
/** /**
@@ -65,8 +70,8 @@ import static org.briarproject.db.ExponentialBackoff.calculateExpiry;
*/ */
abstract class JdbcDatabase implements Database<Connection> { abstract class JdbcDatabase implements Database<Connection> {
private static final int SCHEMA_VERSION = 17; private static final int SCHEMA_VERSION = 18;
private static final int MIN_SCHEMA_VERSION = 17; private static final int MIN_SCHEMA_VERSION = 18;
private static final String CREATE_SETTINGS = private static final String CREATE_SETTINGS =
"CREATE TABLE settings" "CREATE TABLE settings"
@@ -210,64 +215,6 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " maxLatency INT NOT NULL," + " maxLatency INT NOT NULL,"
+ " PRIMARY KEY (transportId))"; + " PRIMARY KEY (transportId))";
private static final String CREATE_TRANSPORT_CONFIGS =
"CREATE TABLE transportConfigs"
+ " (transportId VARCHAR NOT NULL,"
+ " key VARCHAR NOT NULL,"
+ " value VARCHAR NOT NULL,"
+ " PRIMARY KEY (transportId, key),"
+ " FOREIGN KEY (transportId)"
+ " REFERENCES transports (transportId)"
+ " ON DELETE CASCADE)";
private static final String CREATE_TRANSPORT_PROPS =
"CREATE TABLE transportProperties"
+ " (transportId VARCHAR NOT NULL,"
+ " key VARCHAR NOT NULL,"
+ " value VARCHAR NOT NULL,"
+ " PRIMARY KEY (transportId, key),"
+ " FOREIGN KEY (transportId)"
+ " REFERENCES transports (transportId)"
+ " ON DELETE CASCADE)";
private static final String CREATE_TRANSPORT_VERSIONS =
"CREATE TABLE transportVersions"
+ " (contactId INT NOT NULL,"
+ " transportId VARCHAR NOT NULL,"
+ " localVersion BIGINT NOT NULL,"
+ " localAcked BIGINT NOT NULL,"
+ " expiry BIGINT NOT NULL,"
+ " txCount INT NOT NULL,"
+ " PRIMARY KEY (contactId, transportId),"
+ " FOREIGN KEY (contactId)"
+ " REFERENCES contacts (contactId)"
+ " ON DELETE CASCADE,"
+ " FOREIGN KEY (transportId)"
+ " REFERENCES transports (transportId)"
+ " ON DELETE CASCADE)";
private static final String CREATE_CONTACT_TRANSPORT_PROPS =
"CREATE TABLE contactTransportProperties"
+ " (contactId INT NOT NULL,"
+ " transportId VARCHAR NOT NULL," // Not a foreign key
+ " 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_CONTACT_TRANSPORT_VERSIONS =
"CREATE TABLE contactTransportVersions"
+ " (contactId INT NOT NULL,"
+ " transportId VARCHAR NOT NULL," // Not a foreign key
+ " remoteVersion BIGINT NOT NULL,"
+ " remoteAcked BOOLEAN NOT NULL,"
+ " PRIMARY KEY (contactId, transportId),"
+ " FOREIGN KEY (contactId)"
+ " REFERENCES contacts (contactId)"
+ " ON DELETE CASCADE)";
private static final String CREATE_INCOMING_KEYS = private static final String CREATE_INCOMING_KEYS =
"CREATE TABLE incomingKeys" "CREATE TABLE incomingKeys"
+ " (contactId INT NOT NULL," + " (contactId INT NOT NULL,"
@@ -306,6 +253,7 @@ abstract class JdbcDatabase implements Database<Connection> {
// Different database libraries use different names for certain types // Different database libraries use different names for certain types
private final String hashType, binaryType, counterType, secretType; private final String hashType, binaryType, counterType, secretType;
private final SecureRandom random;
private final Clock clock; private final Clock clock;
private final LinkedList<Connection> connections = private final LinkedList<Connection> connections =
@@ -318,22 +266,20 @@ abstract class JdbcDatabase implements Database<Connection> {
protected abstract Connection createConnection() throws SQLException; protected abstract Connection createConnection() throws SQLException;
protected abstract void flushBuffersToDisk(Statement s) throws SQLException;
private final Lock connectionsLock = new ReentrantLock(); private final Lock connectionsLock = new ReentrantLock();
private final Condition connectionsChanged = connectionsLock.newCondition(); private final Condition connectionsChanged = connectionsLock.newCondition();
JdbcDatabase(String hashType, String binaryType, String counterType, JdbcDatabase(String hashType, String binaryType, String counterType,
String secretType, Clock clock) { String secretType, SecureRandom random, Clock clock) {
this.hashType = hashType; this.hashType = hashType;
this.binaryType = binaryType; this.binaryType = binaryType;
this.counterType = counterType; this.counterType = counterType;
this.secretType = secretType; this.secretType = secretType;
this.random = random;
this.clock = clock; this.clock = clock;
} }
protected void open(String driverClass, boolean reopen) throws DbException, protected void open(String driverClass, boolean reopen) throws DbException {
IOException {
// Load the JDBC driver // Load the JDBC driver
try { try {
Class.forName(driverClass); Class.forName(driverClass);
@@ -347,10 +293,8 @@ abstract class JdbcDatabase implements Database<Connection> {
if (!checkSchemaVersion(txn)) throw new DbException(); if (!checkSchemaVersion(txn)) throw new DbException();
} else { } else {
createTables(txn); createTables(txn);
Settings s = new Settings(); storeSchemaVersion(txn);
s.put("schemaVersion", String.valueOf(SCHEMA_VERSION)); storeDeviceId(txn);
s.put("minSchemaVersion", String.valueOf(MIN_SCHEMA_VERSION));
mergeSettings(txn, s, "db");
} }
commitTransaction(txn); commitTransaction(txn);
} catch (DbException e) { } catch (DbException e) {
@@ -360,16 +304,27 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
private boolean checkSchemaVersion(Connection txn) throws DbException { private boolean checkSchemaVersion(Connection txn) throws DbException {
try { Settings s = getSettings(txn, DB_SETTINGS_NAMESPACE);
Settings s = getSettings(txn, "db"); int schemaVersion = s.getInt(SCHEMA_VERSION_KEY, -1);
int schemaVersion = Integer.valueOf(s.get("schemaVersion")); if (schemaVersion == SCHEMA_VERSION) return true;
if (schemaVersion == SCHEMA_VERSION) return true; if (schemaVersion < MIN_SCHEMA_VERSION) return false;
if (schemaVersion < MIN_SCHEMA_VERSION) return false; int minSchemaVersion = s.getInt(MIN_SCHEMA_VERSION_KEY, -1);
int minSchemaVersion = Integer.valueOf(s.get("minSchemaVersion")); return SCHEMA_VERSION >= minSchemaVersion;
return SCHEMA_VERSION >= minSchemaVersion; }
} catch (NumberFormatException e) {
throw new DbException(e); private void storeSchemaVersion(Connection txn) throws DbException {
} Settings s = new Settings();
s.putInt(SCHEMA_VERSION_KEY, SCHEMA_VERSION);
s.putInt(MIN_SCHEMA_VERSION_KEY, MIN_SCHEMA_VERSION);
mergeSettings(txn, s, DB_SETTINGS_NAMESPACE);
}
private void storeDeviceId(Connection txn) throws DbException {
byte[] deviceId = new byte[UniqueId.LENGTH];
random.nextBytes(deviceId);
Settings s = new Settings();
s.put(DEVICE_ID_KEY, StringUtils.toHexString(deviceId));
mergeSettings(txn, s, DEVICE_SETTINGS_NAMESPACE);
} }
private void tryToClose(ResultSet rs) { private void tryToClose(ResultSet rs) {
@@ -405,11 +360,6 @@ abstract class JdbcDatabase implements Database<Connection> {
s.executeUpdate(insertTypeNames(CREATE_OFFERS)); s.executeUpdate(insertTypeNames(CREATE_OFFERS));
s.executeUpdate(insertTypeNames(CREATE_STATUSES)); s.executeUpdate(insertTypeNames(CREATE_STATUSES));
s.executeUpdate(insertTypeNames(CREATE_TRANSPORTS)); s.executeUpdate(insertTypeNames(CREATE_TRANSPORTS));
s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_CONFIGS));
s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_PROPS));
s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_VERSIONS));
s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORT_PROPS));
s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORT_VERSIONS));
s.executeUpdate(insertTypeNames(CREATE_INCOMING_KEYS)); s.executeUpdate(insertTypeNames(CREATE_INCOMING_KEYS));
s.executeUpdate(insertTypeNames(CREATE_OUTGOING_KEYS)); s.executeUpdate(insertTypeNames(CREATE_OUTGOING_KEYS));
s.close(); s.close();
@@ -487,14 +437,9 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
public void commitTransaction(Connection txn) throws DbException { public void commitTransaction(Connection txn) throws DbException {
Statement s = null;
try { try {
txn.commit(); txn.commit();
s = txn.createStatement();
flushBuffersToDisk(s);
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s);
throw new DbException(e); throw new DbException(e);
} }
connectionsLock.lock(); connectionsLock.lock();
@@ -540,6 +485,11 @@ abstract class JdbcDatabase implements Database<Connection> {
if (interrupted) Thread.currentThread().interrupt(); if (interrupted) Thread.currentThread().interrupt();
} }
public DeviceId getDeviceId(Connection txn) throws DbException {
Settings s = getSettings(txn, DEVICE_SETTINGS_NAMESPACE);
return new DeviceId(StringUtils.fromHexString(s.get(DEVICE_ID_KEY)));
}
public ContactId addContact(Connection txn, Author remote, AuthorId local) public ContactId addContact(Connection txn, Author remote, AuthorId local)
throws DbException { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
@@ -589,9 +539,8 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != ids.size()) if (batchAffected.length != ids.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected)
if (batchAffected[i] != 1) throw new DbStateException(); if (rows != 1) throw new DbStateException();
}
ps.close(); ps.close();
} }
// Make groups that are visible to everyone visible to this contact // Make groups that are visible to everyone visible to this contact
@@ -614,9 +563,8 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != ids.size()) if (batchAffected.length != ids.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected)
if (batchAffected[i] != 1) throw new DbStateException(); if (rows != 1) throw new DbStateException();
}
ps.close(); ps.close();
} }
// Create a group version row // Create a group version row
@@ -629,31 +577,6 @@ abstract class JdbcDatabase implements Database<Connection> {
affected = ps.executeUpdate(); affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException(); if (affected != 1) throw new DbStateException();
ps.close(); ps.close();
// Create a transport version row for each local transport
sql = "SELECT transportId FROM transports";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
Collection<String> transports = new ArrayList<String>();
while (rs.next()) transports.add(rs.getString(1));
rs.close();
ps.close();
if (transports.isEmpty()) return c;
sql = "INSERT INTO transportVersions (contactId, transportId,"
+ " localVersion, localAcked, expiry, txCount)"
+ " VALUES (?, ?, 1, 0, 0, 0)";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
for (String t : transports) {
ps.setString(2, t);
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();
return c; return c;
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(rs); tryToClose(rs);
@@ -851,30 +774,6 @@ abstract class JdbcDatabase implements Database<Connection> {
int affected = ps.executeUpdate(); int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException(); if (affected != 1) throw new DbStateException();
ps.close(); ps.close();
// Create a transport version row for each contact
sql = "SELECT contactId FROM contacts";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
Collection<Integer> contacts = new ArrayList<Integer>();
while (rs.next()) contacts.add(rs.getInt(1));
rs.close();
ps.close();
if (contacts.isEmpty()) return true;
sql = "INSERT INTO transportVersions (contactId, transportId,"
+ " localVersion, localAcked, expiry, txCount)"
+ " VALUES (?, ?, 1, 0, 0, 0)";
ps = txn.prepareStatement(sql);
ps.setString(2, t.getString());
for (Integer c : contacts) {
ps.setInt(1, c);
ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
if (batchAffected.length != contacts.size())
throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) {
if (batchAffected[i] != 1) throw new DbStateException();
}
return true; return true;
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(ps); tryToClose(ps);
@@ -920,9 +819,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.addBatch(); ps.addBatch();
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != 3) throw new DbStateException(); if (batchAffected.length != 3) throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected)
if (batchAffected[i] != 1) throw new DbStateException(); if (rows != 1) throw new DbStateException();
}
ps.close(); ps.close();
// Store the outgoing keys // Store the outgoing keys
sql = "INSERT INTO outgoingKeys (contactId, transportId, period," sql = "INSERT INTO outgoingKeys (contactId, transportId, period,"
@@ -1415,62 +1313,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public Map<TransportId, TransportProperties> getLocalProperties(
Connection txn) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT transportId, key, value"
+ " FROM transportProperties"
+ " ORDER BY transportId";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
Map<TransportId, TransportProperties> properties =
new HashMap<TransportId, TransportProperties>();
TransportId lastId = null;
TransportProperties p = null;
while (rs.next()) {
TransportId id = new TransportId(rs.getString(1));
String key = rs.getString(2), value = rs.getString(3);
if (!id.equals(lastId)) {
p = new TransportProperties();
properties.put(id, p);
lastId = id;
}
p.put(key, value);
}
rs.close();
ps.close();
return Collections.unmodifiableMap(properties);
} 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 transportProperties"
+ " WHERE transportId = ?";
ps = txn.prepareStatement(sql);
ps.setString(1, t.getString());
rs = ps.executeQuery();
TransportProperties p = new TransportProperties();
while (rs.next()) p.put(rs.getString(1), rs.getString(2));
rs.close();
ps.close();
return p;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
public Map<MessageId, Metadata> getMessageMetadata(Connection txn, public Map<MessageId, Metadata> getMessageMetadata(Connection txn,
GroupId g) throws DbException { GroupId g) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
@@ -1773,42 +1615,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
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 contactTransportProperties"
+ " WHERE transportId = ?"
+ " ORDER BY contactId";
ps = txn.prepareStatement(sql);
ps.setString(1, t.getString());
rs = ps.executeQuery();
Map<ContactId, TransportProperties> properties =
new HashMap<ContactId, TransportProperties>();
ContactId lastId = null;
TransportProperties p = null;
while (rs.next()) {
ContactId id = new ContactId(rs.getInt(1));
String key = rs.getString(2), value = rs.getString(3);
if (!id.equals(lastId)) {
p = new TransportProperties();
properties.put(id, p);
lastId = id;
}
p.put(key, value);
}
rs.close();
ps.close();
return Collections.unmodifiableMap(properties);
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
public Collection<MessageId> getRequestedMessagesToSend(Connection txn, public Collection<MessageId> getRequestedMessagesToSend(Connection txn,
ContactId c, int maxLength) throws DbException { ContactId c, int maxLength) throws DbException {
long now = clock.currentTimeMillis(); long now = clock.currentTimeMillis();
@@ -1996,48 +1802,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public Collection<TransportAck> getTransportAcks(Connection txn,
ContactId c) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT transportId, remoteVersion"
+ " FROM contactTransportVersions"
+ " WHERE contactId = ? AND remoteAcked = FALSE";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
rs = ps.executeQuery();
List<TransportAck> acks = new ArrayList<TransportAck>();
while (rs.next()) {
TransportId id = new TransportId(rs.getString(1));
acks.add(new TransportAck(id, rs.getLong(2)));
}
rs.close();
ps.close();
if (acks.isEmpty()) return null;
sql = "UPDATE contactTransportVersions SET remoteAcked = TRUE"
+ " WHERE contactId = ? AND transportId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
for (TransportAck a : acks) {
ps.setString(2, a.getId().getString());
ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
if (batchAffected.length != acks.size())
throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) {
if (batchAffected[i] != 1) throw new DbStateException();
}
ps.close();
return Collections.unmodifiableList(acks);
} catch (SQLException e) {
tryToClose(ps);
tryToClose(rs);
throw new DbException(e);
}
}
public Map<ContactId, TransportKeys> getTransportKeys(Connection txn, public Map<ContactId, TransportKeys> getTransportKeys(Connection txn,
TransportId t) throws DbException { TransportId t) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
@@ -2123,72 +1887,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public Collection<TransportUpdate> getTransportUpdates(Connection txn,
ContactId c, int maxLatency) throws DbException {
long now = clock.currentTimeMillis();
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT tp.transportId, key, value, localVersion,"
+ " txCount"
+ " FROM transportProperties AS tp"
+ " JOIN transportVersions AS tv"
+ " ON tp.transportId = tv.transportId"
+ " WHERE tv.contactId = ?"
+ " AND localVersion > localAcked"
+ " AND expiry < ?"
+ " ORDER BY tp.transportId";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setLong(2, now);
rs = ps.executeQuery();
List<TransportUpdate> updates = new ArrayList<TransportUpdate>();
TransportId lastId = null;
TransportProperties p = null;
List<Integer> txCounts = new ArrayList<Integer>();
while (rs.next()) {
TransportId id = new TransportId(rs.getString(1));
String key = rs.getString(2), value = rs.getString(3);
long version = rs.getLong(4);
int txCount = rs.getInt(5);
if (!id.equals(lastId)) {
p = new TransportProperties();
updates.add(new TransportUpdate(id, p, version));
txCounts.add(txCount);
lastId = id;
}
p.put(key, value);
}
rs.close();
ps.close();
if (updates.isEmpty()) return null;
sql = "UPDATE transportVersions"
+ " SET expiry = ?, txCount = txCount + 1"
+ " WHERE contactId = ? AND transportId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(2, c.getInt());
int i = 0;
for (TransportUpdate u : updates) {
int txCount = txCounts.get(i++);
ps.setLong(1, calculateExpiry(now, maxLatency, txCount));
ps.setString(3, u.getId().getString());
ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
if (batchAffected.length != updates.size())
throw new DbStateException();
for (i = 0; i < batchAffected.length; i++) {
if (batchAffected[i] != 1) throw new DbStateException();
}
ps.close();
return Collections.unmodifiableList(updates);
} catch (SQLException e) {
tryToClose(ps);
tryToClose(rs);
throw new DbException(e);
}
}
public Collection<ContactId> getVisibility(Connection txn, GroupId g) public Collection<ContactId> getVisibility(Connection txn, GroupId g)
throws DbException { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
@@ -2245,9 +1943,9 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != acked.size()) if (batchAffected.length != acked.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected) {
if (batchAffected[i] < 0) throw new DbStateException(); if (rows < 0) throw new DbStateException();
if (batchAffected[i] > 1) throw new DbStateException(); if (rows > 1) throw new DbStateException();
} }
ps.close(); ps.close();
} catch (SQLException e) { } catch (SQLException e) {
@@ -2271,76 +1969,9 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != requested.size()) if (batchAffected.length != requested.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows: batchAffected) {
if (batchAffected[i] < 0) throw new DbStateException(); if (rows < 0) throw new DbStateException();
if (batchAffected[i] > 1) throw new DbStateException(); if (rows > 1) throw new DbStateException();
}
ps.close();
} catch (SQLException e) {
tryToClose(ps);
throw new DbException(e);
}
}
public void mergeLocalProperties(Connection txn, TransportId t,
TransportProperties p) throws DbException {
// Merge the new properties with the existing ones
mergeStringMap(txn, t, p, "transportProperties");
// Bump the transport version
PreparedStatement ps = null;
try {
String sql = "UPDATE transportVersions"
+ " SET localVersion = localVersion + 1, expiry = 0"
+ " WHERE transportId = ?";
ps = txn.prepareStatement(sql);
ps.setString(1, t.getString());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
throw new DbException(e);
}
}
private void mergeStringMap(Connection txn, TransportId t,
Map<String, String> m, String tableName) throws DbException {
PreparedStatement ps = null;
try {
// Update any properties that already exist
String sql = "UPDATE " + tableName + " SET value = ?"
+ " WHERE transportId = ? AND key = ?";
ps = txn.prepareStatement(sql);
ps.setString(2, t.getString());
for (Entry<String, String> e : m.entrySet()) {
ps.setString(1, e.getValue());
ps.setString(3, e.getKey());
ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
if (batchAffected.length != m.size()) throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) {
if (batchAffected[i] < 0) throw new DbStateException();
if (batchAffected[i] > 1) throw new DbStateException();
}
// Insert any properties that don't already exist
sql = "INSERT INTO " + tableName + " (transportId, key, value)"
+ " VALUES (?, ?, ?)";
ps = txn.prepareStatement(sql);
ps.setString(1, t.getString());
int updateIndex = 0, inserted = 0;
for (Entry<String, String> e : m.entrySet()) {
if (batchAffected[updateIndex] == 0) {
ps.setString(2, e.getKey());
ps.setString(3, e.getValue());
ps.addBatch();
inserted++;
}
updateIndex++;
}
batchAffected = ps.executeBatch();
if (batchAffected.length != inserted) throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) {
if (batchAffected[i] != 1) throw new DbStateException();
} }
ps.close(); ps.close();
} catch (SQLException e) { } catch (SQLException e) {
@@ -2383,9 +2014,9 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != removed.size()) if (batchAffected.length != removed.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected) {
if (batchAffected[i] < 0) throw new DbStateException(); if (rows < 0) throw new DbStateException();
if (batchAffected[i] > 1) throw new DbStateException(); if (rows > 1) throw new DbStateException();
} }
ps.close(); ps.close();
} }
@@ -2403,9 +2034,9 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != retained.size()) if (batchAffected.length != retained.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected) {
if (batchAffected[i] < 0) throw new DbStateException(); if (rows < 0) throw new DbStateException();
if (batchAffected[i] > 1) throw new DbStateException(); if (rows > 1) throw new DbStateException();
} }
// Insert any keys that don't already exist // Insert any keys that don't already exist
sql = "INSERT INTO " + tableName sql = "INSERT INTO " + tableName
@@ -2425,9 +2056,8 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
batchAffected = ps.executeBatch(); batchAffected = ps.executeBatch();
if (batchAffected.length != inserted) throw new DbStateException(); if (batchAffected.length != inserted) throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected)
if (batchAffected[i] != 1) throw new DbStateException(); if (rows != 1) throw new DbStateException();
}
ps.close(); ps.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(ps); tryToClose(ps);
@@ -2451,9 +2081,9 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != s.size()) throw new DbStateException(); if (batchAffected.length != s.size()) throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected) {
if (batchAffected[i] < 0) throw new DbStateException(); if (rows < 0) throw new DbStateException();
if (batchAffected[i] > 1) throw new DbStateException(); if (rows > 1) throw new DbStateException();
} }
// Insert any settings that don't already exist // Insert any settings that don't already exist
sql = "INSERT INTO settings (key, value, namespace)" sql = "INSERT INTO settings (key, value, namespace)"
@@ -2472,9 +2102,8 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
batchAffected = ps.executeBatch(); batchAffected = ps.executeBatch();
if (batchAffected.length != inserted) throw new DbStateException(); if (batchAffected.length != inserted) throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected)
if (batchAffected[i] != 1) throw new DbStateException(); if (rows != 1) throw new DbStateException();
}
ps.close(); ps.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(ps); tryToClose(ps);
@@ -2586,9 +2215,8 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != visible.size()) if (batchAffected.length != visible.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected)
if (batchAffected[i] != 1) throw new DbStateException(); if (rows != 1) throw new DbStateException();
}
ps.close(); ps.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(ps); tryToClose(ps);
@@ -2662,9 +2290,8 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != requested.size()) if (batchAffected.length != requested.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected)
if (batchAffected[i] != 1) throw new DbStateException(); if (rows != 1) throw new DbStateException();
}
ps.close(); ps.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(ps); tryToClose(ps);
@@ -2734,7 +2361,7 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
public void setContactStatus(Connection txn, ContactId c, StorageStatus s) public void setContactStatus(Connection txn, ContactId c, StorageStatus s)
throws DbException { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "UPDATE contacts SET status = ? WHERE contactId = ?"; String sql = "UPDATE contacts SET status = ? WHERE contactId = ?";
@@ -2769,7 +2396,7 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
public void setMessageValidity(Connection txn, MessageId m, boolean valid) public void setMessageValidity(Connection txn, MessageId m, boolean valid)
throws DbException { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "UPDATE messages SET valid = ? WHERE messageId = ?"; String sql = "UPDATE messages SET valid = ? WHERE messageId = ?";
@@ -2856,9 +2483,8 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != removed.size()) if (batchAffected.length != removed.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected)
if (batchAffected[i] < 0) throw new DbStateException(); if (rows < 0) throw new DbStateException();
}
ps.close(); ps.close();
} }
// Delete the existing subscriptions, if any // Delete the existing subscriptions, if any
@@ -2882,130 +2508,8 @@ abstract class JdbcDatabase implements Database<Connection> {
int[] batchAffected = ps.executeBatch(); int[] batchAffected = ps.executeBatch();
if (batchAffected.length != groups.size()) if (batchAffected.length != groups.size())
throw new DbStateException(); throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) { for (int rows : batchAffected)
if (batchAffected[i] != 1) throw new DbStateException(); if (rows != 1) throw new DbStateException();
}
ps.close();
return true;
} catch (SQLException e) {
tryToClose(ps);
tryToClose(rs);
throw new DbException(e);
}
}
public void setRemoteProperties(Connection txn, ContactId c,
Map<TransportId, TransportProperties> p) throws DbException {
PreparedStatement ps = null;
try {
// Delete the existing properties, if any
String sql = "DELETE FROM contactTransportProperties"
+ " WHERE contactId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.executeUpdate();
ps.close();
// Store the new 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 : p.entrySet()) {
ps.setString(2, e.getKey().getString());
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();
} catch (SQLException e) {
tryToClose(ps);
throw new DbException(e);
}
}
public boolean setRemoteProperties(Connection txn, ContactId c,
TransportId t, TransportProperties p, long version)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
// Find the existing version, if any
String sql = "SELECT NULL FROM contactTransportVersions"
+ " WHERE contactId = ? AND transportId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setString(2, t.getString());
rs = ps.executeQuery();
boolean found = rs.next();
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
// Mark the update as needing to be acked
if (found) {
// The row exists - update it
sql = "UPDATE contactTransportVersions"
+ " SET remoteVersion = ?, remoteAcked = FALSE"
+ " WHERE contactId = ? AND transportId = ?"
+ " AND remoteVersion < ?";
ps = txn.prepareStatement(sql);
ps.setLong(1, version);
ps.setInt(2, c.getInt());
ps.setString(3, t.getString());
ps.setLong(4, version);
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
// Return false if the update is obsolete
if (affected == 0) return false;
} else {
// The row doesn't exist - create it
sql = "INSERT INTO contactTransportVersions (contactId,"
+ " transportId, remoteVersion, remoteAcked)"
+ " VALUES (?, ?, ?, FALSE)";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setString(2, t.getString());
ps.setLong(3, version);
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
}
// Delete the existing properties, if any
sql = "DELETE FROM contactTransportProperties"
+ " WHERE contactId = ? AND transportId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setString(2, t.getString());
ps.executeUpdate();
ps.close();
// Store the new properties, if any
if (p.isEmpty()) return true;
sql = "INSERT INTO contactTransportProperties"
+ " (contactId, transportId, key, value)"
+ " VALUES (?, ?, ?, ?)";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setString(2, t.getString());
for (Entry<String, String> e : p.entrySet()) {
ps.setString(3, e.getKey());
ps.setString(4, e.getValue());
ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
if (batchAffected.length != p.size()) throw new DbStateException();
for (int i = 0; i < batchAffected.length; i++) {
if (batchAffected[i] != 1) throw new DbStateException();
}
ps.close(); ps.close();
return true; return true;
} catch (SQLException e) { } catch (SQLException e) {
@@ -3036,28 +2540,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public void setTransportUpdateAcked(Connection txn, ContactId c,
TransportId t, long version) throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE transportVersions SET localAcked = ?"
+ " WHERE contactId = ? AND transportId = ?"
+ " AND localAcked < ? AND localVersion >= ?";
ps = txn.prepareStatement(sql);
ps.setLong(1, version);
ps.setInt(2, c.getInt());
ps.setString(3, t.getString());
ps.setLong(4, version);
ps.setLong(5, version);
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
throw new DbException(e);
}
}
public void setVisibleToAll(Connection txn, GroupId g, boolean all) public void setVisibleToAll(Connection txn, GroupId g, boolean all)
throws DbException { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;

View File

@@ -16,6 +16,8 @@ import org.briarproject.api.system.Clock;
import javax.inject.Singleton; import javax.inject.Singleton;
import static org.briarproject.forum.ForumManagerImpl.CLIENT_ID;
public class ForumModule extends AbstractModule { public class ForumModule extends AbstractModule {
@Override @Override
@@ -26,16 +28,14 @@ public class ForumModule extends AbstractModule {
@Provides @Singleton @Provides @Singleton
ForumPostValidator getValidator(ValidationManager validationManager, ForumPostValidator getValidator(ValidationManager validationManager,
ForumManager forumManager, CryptoComponent crypto, CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
BdfReaderFactory bdfReaderFactory,
BdfWriterFactory bdfWriterFactory, BdfWriterFactory bdfWriterFactory,
ObjectReader<Author> authorReader, MetadataEncoder metadataEncoder, ObjectReader<Author> authorReader, MetadataEncoder metadataEncoder,
Clock clock) { Clock clock) {
ForumPostValidator validator = new ForumPostValidator(crypto, ForumPostValidator validator = new ForumPostValidator(crypto,
bdfReaderFactory, bdfWriterFactory, authorReader, bdfReaderFactory, bdfWriterFactory, authorReader,
metadataEncoder, clock); metadataEncoder, clock);
validationManager.registerMessageValidator(forumManager.getClientId(), validationManager.registerMessageValidator(CLIENT_ID, validator);
validator);
return validator; return validator;
} }
} }

View File

@@ -1,7 +1,5 @@
package org.briarproject.invitation; package org.briarproject.invitation;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
@@ -17,7 +15,6 @@ import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.plugins.ConnectionManager; import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.property.TransportPropertyManager;
import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupFactory;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager; import org.briarproject.api.transport.KeyManager;
@@ -28,7 +25,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
@@ -47,17 +43,12 @@ class AliceConnector extends Connector {
StreamWriterFactory streamWriterFactory, StreamWriterFactory streamWriterFactory,
AuthorFactory authorFactory, GroupFactory groupFactory, AuthorFactory authorFactory, GroupFactory groupFactory,
KeyManager keyManager, ConnectionManager connectionManager, KeyManager keyManager, ConnectionManager connectionManager,
ContactManager contactManager, ContactManager contactManager, Clock clock, ConnectorGroup group,
TransportPropertyManager transportPropertyManager, Clock clock, DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
boolean reuseConnection, ConnectorGroup group, DuplexPlugin plugin,
LocalAuthor localAuthor,
Map<TransportId, TransportProperties> localProps,
PseudoRandom random) {
super(crypto, bdfReaderFactory, bdfWriterFactory, streamReaderFactory, super(crypto, bdfReaderFactory, bdfWriterFactory, streamReaderFactory,
streamWriterFactory, authorFactory, groupFactory, streamWriterFactory, authorFactory, groupFactory, keyManager,
keyManager, connectionManager, contactManager, connectionManager, contactManager, clock, group, plugin,
transportPropertyManager, clock, reuseConnection, group, localAuthor, random);
plugin, localAuthor, localProps, random);
} }
@Override @Override
@@ -152,20 +143,14 @@ class AliceConnector extends Connector {
// Derive the invitation nonces // Derive the invitation nonces
byte[] aliceNonce = crypto.deriveSignatureNonce(master, true); byte[] aliceNonce = crypto.deriveSignatureNonce(master, true);
byte[] bobNonce = crypto.deriveSignatureNonce(master, false); byte[] bobNonce = crypto.deriveSignatureNonce(master, false);
// Exchange pseudonyms, signed nonces, timestamps and transports // Exchange pseudonyms, signed nonces, and timestamps
Author remoteAuthor; Author remoteAuthor;
long remoteTimestamp; long remoteTimestamp;
Map<TransportId, TransportProperties> remoteProps;
boolean remoteReuseConnection;
try { try {
sendPseudonym(w, aliceNonce); sendPseudonym(w, aliceNonce);
sendTimestamp(w, localTimestamp); sendTimestamp(w, localTimestamp);
sendTransportProperties(w);
sendConfirmation(w, reuseConnection);
remoteAuthor = receivePseudonym(r, bobNonce); remoteAuthor = receivePseudonym(r, bobNonce);
remoteTimestamp = receiveTimestamp(r); remoteTimestamp = receiveTimestamp(r);
remoteProps = receiveTransportProperties(r);
remoteReuseConnection = receiveConfirmation(r);
// Close the outgoing stream and expect EOF on the incoming stream // Close the outgoing stream and expect EOF on the incoming stream
w.close(); w.close();
if (!r.eof()) LOG.warning("Unexpected data at end of connection"); if (!r.eof()) LOG.warning("Unexpected data at end of connection");
@@ -182,18 +167,17 @@ class AliceConnector extends Connector {
} }
// The agreed timestamp is the minimum of the peers' timestamps // The agreed timestamp is the minimum of the peers' timestamps
long timestamp = Math.min(localTimestamp, remoteTimestamp); long timestamp = Math.min(localTimestamp, remoteTimestamp);
// Add the contact and store the transports // Add the contact
try { try {
addContact(remoteAuthor, remoteProps, master, timestamp, true); addContact(remoteAuthor, master, timestamp, true);
} catch (DbException e) { } catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true); tryToClose(conn, true);
group.pseudonymExchangeFailed(); group.pseudonymExchangeFailed();
return; return;
} }
// Reuse the connection as a transport connection if both peers agree // Reuse the connection as a transport connection
if (reuseConnection && remoteReuseConnection) reuseConnection(conn); reuseConnection(conn);
else tryToClose(conn, false);
// Pseudonym exchange succeeded // Pseudonym exchange succeeded
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info(pluginName + " pseudonym exchange succeeded"); LOG.info(pluginName + " pseudonym exchange succeeded");

View File

@@ -1,7 +1,5 @@
package org.briarproject.invitation; package org.briarproject.invitation;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
@@ -17,7 +15,6 @@ import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.plugins.ConnectionManager; import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.property.TransportPropertyManager;
import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupFactory;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager; import org.briarproject.api.transport.KeyManager;
@@ -28,7 +25,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
@@ -47,17 +43,12 @@ class BobConnector extends Connector {
StreamWriterFactory streamWriterFactory, StreamWriterFactory streamWriterFactory,
AuthorFactory authorFactory, GroupFactory groupFactory, AuthorFactory authorFactory, GroupFactory groupFactory,
KeyManager keyManager, ConnectionManager connectionManager, KeyManager keyManager, ConnectionManager connectionManager,
ContactManager contactManager, ContactManager contactManager, Clock clock, ConnectorGroup group,
TransportPropertyManager transportPropertyManager, Clock clock, DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
boolean reuseConnection, ConnectorGroup group, DuplexPlugin plugin,
LocalAuthor localAuthor,
Map<TransportId, TransportProperties> localProps,
PseudoRandom random) {
super(crypto, bdfReaderFactory, bdfWriterFactory, streamReaderFactory, super(crypto, bdfReaderFactory, bdfWriterFactory, streamReaderFactory,
streamWriterFactory, authorFactory, groupFactory, streamWriterFactory, authorFactory, groupFactory, keyManager,
keyManager, connectionManager, contactManager, connectionManager, contactManager, clock, group, plugin,
transportPropertyManager, clock, reuseConnection, group, localAuthor, random);
plugin, localAuthor, localProps, random);
} }
@Override @Override
@@ -152,20 +143,14 @@ class BobConnector extends Connector {
// Derive the nonces // Derive the nonces
byte[] aliceNonce = crypto.deriveSignatureNonce(master, true); byte[] aliceNonce = crypto.deriveSignatureNonce(master, true);
byte[] bobNonce = crypto.deriveSignatureNonce(master, false); byte[] bobNonce = crypto.deriveSignatureNonce(master, false);
// Exchange pseudonyms, signed nonces, timestamps and transports // Exchange pseudonyms, signed nonces and timestamps
Author remoteAuthor; Author remoteAuthor;
long remoteTimestamp; long remoteTimestamp;
Map<TransportId, TransportProperties> remoteProps;
boolean remoteReuseConnection;
try { try {
remoteAuthor = receivePseudonym(r, aliceNonce); remoteAuthor = receivePseudonym(r, aliceNonce);
remoteTimestamp = receiveTimestamp(r); remoteTimestamp = receiveTimestamp(r);
remoteProps = receiveTransportProperties(r);
remoteReuseConnection = receiveConfirmation(r);
sendPseudonym(w, bobNonce); sendPseudonym(w, bobNonce);
sendTimestamp(w, localTimestamp); sendTimestamp(w, localTimestamp);
sendTransportProperties(w);
sendConfirmation(w, reuseConnection);
// Close the outgoing stream and expect EOF on the incoming stream // Close the outgoing stream and expect EOF on the incoming stream
w.close(); w.close();
if (!r.eof()) LOG.warning("Unexpected data at end of connection"); if (!r.eof()) LOG.warning("Unexpected data at end of connection");
@@ -182,18 +167,17 @@ class BobConnector extends Connector {
} }
// The agreed timestamp is the minimum of the peers' timestamps // The agreed timestamp is the minimum of the peers' timestamps
long timestamp = Math.min(localTimestamp, remoteTimestamp); long timestamp = Math.min(localTimestamp, remoteTimestamp);
// Add the contact and store the transports // Add the contact
try { try {
addContact(remoteAuthor, remoteProps, master, timestamp, false); addContact(remoteAuthor, master, timestamp, false);
} catch (DbException e) { } catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn, true); tryToClose(conn, true);
group.pseudonymExchangeFailed(); group.pseudonymExchangeFailed();
return; return;
} }
// Reuse the connection as a transport connection if both peers agree // Reuse the connection as a transport connection
if (reuseConnection && remoteReuseConnection) reuseConnection(conn); reuseConnection(conn);
else tryToClose(conn, false);
// Pseudonym exchange succeeded // Pseudonym exchange succeeded
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info(pluginName + " pseudonym exchange succeeded"); LOG.info(pluginName + " pseudonym exchange succeeded");

View File

@@ -2,7 +2,6 @@ package org.briarproject.invitation;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
@@ -23,7 +22,6 @@ import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.plugins.ConnectionManager; import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.property.TransportPropertyManager;
import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupFactory;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager; import org.briarproject.api.transport.KeyManager;
@@ -33,16 +31,10 @@ import org.briarproject.api.transport.StreamWriterFactory;
import java.io.IOException; import java.io.IOException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger; import java.util.logging.Logger;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.api.TransportPropertyConstants.MAX_TRANSPORT_ID_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
@@ -64,13 +56,10 @@ abstract class Connector extends Thread {
protected final KeyManager keyManager; protected final KeyManager keyManager;
protected final ConnectionManager connectionManager; protected final ConnectionManager connectionManager;
protected final ContactManager contactManager; protected final ContactManager contactManager;
protected final TransportPropertyManager transportPropertyManager;
protected final Clock clock; protected final Clock clock;
protected final boolean reuseConnection;
protected final ConnectorGroup group; protected final ConnectorGroup group;
protected final DuplexPlugin plugin; protected final DuplexPlugin plugin;
protected final LocalAuthor localAuthor; protected final LocalAuthor localAuthor;
protected final Map<TransportId, TransportProperties> localProps;
protected final PseudoRandom random; protected final PseudoRandom random;
protected final String pluginName; protected final String pluginName;
@@ -87,12 +76,8 @@ abstract class Connector extends Thread {
StreamWriterFactory streamWriterFactory, StreamWriterFactory streamWriterFactory,
AuthorFactory authorFactory, GroupFactory groupFactory, AuthorFactory authorFactory, GroupFactory groupFactory,
KeyManager keyManager, ConnectionManager connectionManager, KeyManager keyManager, ConnectionManager connectionManager,
ContactManager contactManager, ContactManager contactManager, Clock clock, ConnectorGroup group,
TransportPropertyManager transportPropertyManager, Clock clock, DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
boolean reuseConnection, ConnectorGroup group, DuplexPlugin plugin,
LocalAuthor localAuthor,
Map<TransportId, TransportProperties> localProps,
PseudoRandom random) {
super("Connector"); super("Connector");
this.crypto = crypto; this.crypto = crypto;
this.bdfReaderFactory = bdfReaderFactory; this.bdfReaderFactory = bdfReaderFactory;
@@ -104,13 +89,10 @@ abstract class Connector extends Thread {
this.keyManager = keyManager; this.keyManager = keyManager;
this.connectionManager = connectionManager; this.connectionManager = connectionManager;
this.contactManager = contactManager; this.contactManager = contactManager;
this.transportPropertyManager = transportPropertyManager;
this.clock = clock; this.clock = clock;
this.reuseConnection = reuseConnection;
this.group = group; this.group = group;
this.plugin = plugin; this.plugin = plugin;
this.localAuthor = localAuthor; this.localAuthor = localAuthor;
this.localProps = localProps;
this.random = random; this.random = random;
pluginName = plugin.getClass().getName(); pluginName = plugin.getClass().getName();
keyPair = crypto.generateAgreementKeyPair(); keyPair = crypto.generateAgreementKeyPair();
@@ -233,57 +215,14 @@ abstract class Connector extends Thread {
return timestamp; return timestamp;
} }
protected void sendTransportProperties(BdfWriter w) throws IOException { protected ContactId addContact(Author remoteAuthor, SecretKey master,
w.writeListStart();
for (Entry<TransportId, TransportProperties> e :
localProps.entrySet()) {
w.writeString(e.getKey().getString());
w.writeDictionary(e.getValue());
}
w.writeListEnd();
w.flush();
if (LOG.isLoggable(INFO))
LOG.info(pluginName + " sent transport properties");
}
protected Map<TransportId, TransportProperties> receiveTransportProperties(
BdfReader r) throws IOException {
Map<TransportId, TransportProperties> remoteProps =
new HashMap<TransportId, TransportProperties>();
r.readListStart();
while (!r.hasListEnd()) {
String idString = r.readString(MAX_TRANSPORT_ID_LENGTH);
if (idString.length() == 0) throw new FormatException();
TransportId id = new TransportId(idString);
Map<String, String> p = new HashMap<String, String>();
r.readDictionaryStart();
for (int i = 0; !r.hasDictionaryEnd(); i++) {
if (i == MAX_PROPERTIES_PER_TRANSPORT)
throw new FormatException();
String key = r.readString(MAX_PROPERTY_LENGTH);
String value = r.readString(MAX_PROPERTY_LENGTH);
p.put(key, value);
}
r.readDictionaryEnd();
remoteProps.put(id, new TransportProperties(p));
}
r.readListEnd();
if (LOG.isLoggable(INFO))
LOG.info(pluginName + " received transport properties");
return remoteProps;
}
protected void addContact(Author remoteAuthor,
Map<TransportId, TransportProperties> remoteProps, SecretKey master,
long timestamp, boolean alice) throws DbException { long timestamp, boolean alice) throws DbException {
// Add the contact to the database // Add the contact to the database
contactId = contactManager.addContact(remoteAuthor, contactId = contactManager.addContact(remoteAuthor,
localAuthor.getId()); localAuthor.getId());
// Store the remote transport properties // Derive transport keys
transportPropertyManager.setRemoteProperties(contactId, remoteProps); keyManager.addContact(contactId, master, timestamp, alice);
// Derive transport keys for each transport shared with the contact return contactId;
keyManager.addContact(contactId, remoteProps.keySet(), master,
timestamp, alice);
} }
protected void tryToClose(DuplexTransportConnection conn, protected void tryToClose(DuplexTransportConnection conn,

View File

@@ -1,7 +1,5 @@
package org.briarproject.invitation; package org.briarproject.invitation;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
@@ -19,7 +17,6 @@ import org.briarproject.api.invitation.InvitationTask;
import org.briarproject.api.plugins.ConnectionManager; import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.PluginManager; import org.briarproject.api.plugins.PluginManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.property.TransportPropertyManager;
import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupFactory;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager; import org.briarproject.api.transport.KeyManager;
@@ -28,7 +25,6 @@ import org.briarproject.api.transport.StreamWriterFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -57,12 +53,10 @@ class ConnectorGroup extends Thread implements InvitationTask {
private final ConnectionManager connectionManager; private final ConnectionManager connectionManager;
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final ContactManager contactManager; private final ContactManager contactManager;
private final TransportPropertyManager transportPropertyManager;
private final Clock clock; private final Clock clock;
private final PluginManager pluginManager; private final PluginManager pluginManager;
private final AuthorId localAuthorId; private final AuthorId localAuthorId;
private final int localInvitationCode, remoteInvitationCode; private final int localInvitationCode, remoteInvitationCode;
private final boolean reuseConnection;
private final Collection<InvitationListener> listeners; private final Collection<InvitationListener> listeners;
private final AtomicBoolean connected; private final AtomicBoolean connected;
private final CountDownLatch localConfirmationLatch; private final CountDownLatch localConfirmationLatch;
@@ -83,10 +77,8 @@ class ConnectorGroup extends Thread implements InvitationTask {
AuthorFactory authorFactory, GroupFactory groupFactory, AuthorFactory authorFactory, GroupFactory groupFactory,
KeyManager keyManager, ConnectionManager connectionManager, KeyManager keyManager, ConnectionManager connectionManager,
IdentityManager identityManager, ContactManager contactManager, IdentityManager identityManager, ContactManager contactManager,
TransportPropertyManager transportPropertyManager, Clock clock, Clock clock, PluginManager pluginManager, AuthorId localAuthorId,
PluginManager pluginManager, AuthorId localAuthorId, int localInvitationCode, int remoteInvitationCode) {
int localInvitationCode, int remoteInvitationCode,
boolean reuseConnection) {
super("ConnectorGroup"); super("ConnectorGroup");
this.crypto = crypto; this.crypto = crypto;
this.bdfReaderFactory = bdfReaderFactory; this.bdfReaderFactory = bdfReaderFactory;
@@ -99,13 +91,11 @@ class ConnectorGroup extends Thread implements InvitationTask {
this.connectionManager = connectionManager; this.connectionManager = connectionManager;
this.identityManager = identityManager; this.identityManager = identityManager;
this.contactManager = contactManager; this.contactManager = contactManager;
this.transportPropertyManager = transportPropertyManager;
this.clock = clock; this.clock = clock;
this.pluginManager = pluginManager; this.pluginManager = pluginManager;
this.localAuthorId = localAuthorId; this.localAuthorId = localAuthorId;
this.localInvitationCode = localInvitationCode; this.localInvitationCode = localInvitationCode;
this.remoteInvitationCode = remoteInvitationCode; this.remoteInvitationCode = remoteInvitationCode;
this.reuseConnection = reuseConnection;
listeners = new CopyOnWriteArrayList<InvitationListener>(); listeners = new CopyOnWriteArrayList<InvitationListener>();
connected = new AtomicBoolean(false); connected = new AtomicBoolean(false);
localConfirmationLatch = new CountDownLatch(1); localConfirmationLatch = new CountDownLatch(1);
@@ -136,11 +126,9 @@ class ConnectorGroup extends Thread implements InvitationTask {
@Override @Override
public void run() { public void run() {
LocalAuthor localAuthor; LocalAuthor localAuthor;
Map<TransportId, TransportProperties> localProps; // Load the local pseudonym
// Load the local pseudonym and transport properties
try { try {
localAuthor = identityManager.getLocalAuthor(localAuthorId); localAuthor = identityManager.getLocalAuthor(localAuthorId);
localProps = transportPropertyManager.getLocalProperties();
} catch (DbException e) { } catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
lock.lock(); lock.lock();
@@ -157,15 +145,13 @@ class ConnectorGroup extends Thread implements InvitationTask {
// Alice is the party with the smaller invitation code // Alice is the party with the smaller invitation code
if (localInvitationCode < remoteInvitationCode) { if (localInvitationCode < remoteInvitationCode) {
for (DuplexPlugin plugin : pluginManager.getInvitationPlugins()) { for (DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
Connector c = createAliceConnector(plugin, localAuthor, Connector c = createAliceConnector(plugin, localAuthor);
localProps);
connectors.add(c); connectors.add(c);
c.start(); c.start();
} }
} else { } else {
for (DuplexPlugin plugin: pluginManager.getInvitationPlugins()) { for (DuplexPlugin plugin: pluginManager.getInvitationPlugins()) {
Connector c = createBobConnector(plugin, localAuthor, Connector c = createBobConnector(plugin, localAuthor);
localProps);
connectors.add(c); connectors.add(c);
c.start(); c.start();
} }
@@ -190,27 +176,23 @@ class ConnectorGroup extends Thread implements InvitationTask {
} }
private Connector createAliceConnector(DuplexPlugin plugin, private Connector createAliceConnector(DuplexPlugin plugin,
LocalAuthor localAuthor, LocalAuthor localAuthor) {
Map<TransportId, TransportProperties> localProps) {
PseudoRandom random = crypto.getPseudoRandom(localInvitationCode, PseudoRandom random = crypto.getPseudoRandom(localInvitationCode,
remoteInvitationCode); remoteInvitationCode);
return new AliceConnector(crypto, bdfReaderFactory, bdfWriterFactory, return new AliceConnector(crypto, bdfReaderFactory, bdfWriterFactory,
streamReaderFactory, streamWriterFactory, authorFactory, streamReaderFactory, streamWriterFactory, authorFactory,
groupFactory, keyManager, connectionManager, contactManager, groupFactory, keyManager, connectionManager, contactManager,
transportPropertyManager, clock, reuseConnection, this, plugin, clock, this, plugin, localAuthor, random);
localAuthor, localProps, random);
} }
private Connector createBobConnector(DuplexPlugin plugin, private Connector createBobConnector(DuplexPlugin plugin,
LocalAuthor localAuthor, LocalAuthor localAuthor) {
Map<TransportId, TransportProperties> localProps) {
PseudoRandom random = crypto.getPseudoRandom(remoteInvitationCode, PseudoRandom random = crypto.getPseudoRandom(remoteInvitationCode,
localInvitationCode); localInvitationCode);
return new BobConnector(crypto, bdfReaderFactory, bdfWriterFactory, return new BobConnector(crypto, bdfReaderFactory, bdfWriterFactory,
streamReaderFactory, streamWriterFactory, authorFactory, streamReaderFactory, streamWriterFactory, authorFactory,
groupFactory, keyManager, connectionManager, contactManager, groupFactory, keyManager, connectionManager, contactManager,
transportPropertyManager, clock, reuseConnection, this, plugin, clock, this, plugin, localAuthor, random);
localAuthor, localProps, random);
} }
public void localConfirmationSucceeded() { public void localConfirmationSucceeded() {

View File

@@ -11,7 +11,6 @@ import org.briarproject.api.invitation.InvitationTask;
import org.briarproject.api.invitation.InvitationTaskFactory; import org.briarproject.api.invitation.InvitationTaskFactory;
import org.briarproject.api.plugins.ConnectionManager; import org.briarproject.api.plugins.ConnectionManager;
import org.briarproject.api.plugins.PluginManager; import org.briarproject.api.plugins.PluginManager;
import org.briarproject.api.property.TransportPropertyManager;
import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupFactory;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.api.transport.KeyManager; import org.briarproject.api.transport.KeyManager;
@@ -33,7 +32,6 @@ class InvitationTaskFactoryImpl implements InvitationTaskFactory {
private final ConnectionManager connectionManager; private final ConnectionManager connectionManager;
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final ContactManager contactManager; private final ContactManager contactManager;
private final TransportPropertyManager transportPropertyManager;
private final Clock clock; private final Clock clock;
private final PluginManager pluginManager; private final PluginManager pluginManager;
@@ -45,7 +43,6 @@ class InvitationTaskFactoryImpl implements InvitationTaskFactory {
AuthorFactory authorFactory, GroupFactory groupFactory, AuthorFactory authorFactory, GroupFactory groupFactory,
KeyManager keyManager, ConnectionManager connectionManager, KeyManager keyManager, ConnectionManager connectionManager,
IdentityManager identityManager, ContactManager contactManager, IdentityManager identityManager, ContactManager contactManager,
TransportPropertyManager transportPropertyManager,
Clock clock, PluginManager pluginManager) { Clock clock, PluginManager pluginManager) {
this.crypto = crypto; this.crypto = crypto;
this.bdfReaderFactory = bdfReaderFactory; this.bdfReaderFactory = bdfReaderFactory;
@@ -58,17 +55,16 @@ class InvitationTaskFactoryImpl implements InvitationTaskFactory {
this.connectionManager = connectionManager; this.connectionManager = connectionManager;
this.identityManager = identityManager; this.identityManager = identityManager;
this.contactManager = contactManager; this.contactManager = contactManager;
this.transportPropertyManager = transportPropertyManager;
this.clock = clock; this.clock = clock;
this.pluginManager = pluginManager; this.pluginManager = pluginManager;
} }
public InvitationTask createTask(AuthorId localAuthorId, int localCode, public InvitationTask createTask(AuthorId localAuthorId, int localCode,
int remoteCode, boolean reuseConnection) { int remoteCode) {
return new ConnectorGroup(crypto, bdfReaderFactory, bdfWriterFactory, return new ConnectorGroup(crypto, bdfReaderFactory, bdfWriterFactory,
streamReaderFactory, streamWriterFactory, authorFactory, streamReaderFactory, streamWriterFactory, authorFactory,
groupFactory, keyManager, connectionManager, identityManager, groupFactory, keyManager, connectionManager, identityManager,
contactManager, transportPropertyManager, clock, pluginManager, contactManager, clock, pluginManager, localAuthorId, localCode,
localAuthorId, localCode, remoteCode, reuseConnection); remoteCode);
} }
} }

View File

@@ -1,11 +1,12 @@
package org.briarproject.lifecycle; package org.briarproject.lifecycle;
import static java.util.logging.Level.INFO; import org.briarproject.api.db.DatabaseComponent;
import static java.util.logging.Level.WARNING; import org.briarproject.api.db.DbException;
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING; import org.briarproject.api.event.EventBus;
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.DB_ERROR; import org.briarproject.api.event.ShutdownEvent;
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR; import org.briarproject.api.lifecycle.LifecycleManager;
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SUCCESS; import org.briarproject.api.lifecycle.Service;
import org.briarproject.api.system.Clock;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
@@ -17,13 +18,12 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import org.briarproject.api.db.DatabaseComponent; import static java.util.logging.Level.INFO;
import org.briarproject.api.db.DbException; import static java.util.logging.Level.WARNING;
import org.briarproject.api.event.EventBus; import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
import org.briarproject.api.event.ShutdownEvent; import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.DB_ERROR;
import org.briarproject.api.lifecycle.LifecycleManager; import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR;
import org.briarproject.api.lifecycle.Service; import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
import org.briarproject.api.system.Clock;
class LifecycleManagerImpl implements LifecycleManager { class LifecycleManagerImpl implements LifecycleManager {
@@ -98,9 +98,6 @@ class LifecycleManagerImpl implements LifecycleManager {
} catch (DbException e) { } catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return DB_ERROR; return DB_ERROR;
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return DB_ERROR;
} finally { } finally {
startStopSemaphore.release(); startStopSemaphore.release();
} }

View File

@@ -13,6 +13,8 @@ import org.briarproject.api.system.Clock;
import javax.inject.Singleton; import javax.inject.Singleton;
import static org.briarproject.messaging.MessagingManagerImpl.CLIENT_ID;
public class MessagingModule extends AbstractModule { public class MessagingModule extends AbstractModule {
@Override @Override
@@ -22,14 +24,11 @@ public class MessagingModule extends AbstractModule {
@Provides @Singleton @Provides @Singleton
PrivateMessageValidator getValidator(ValidationManager validationManager, PrivateMessageValidator getValidator(ValidationManager validationManager,
MessagingManager messagingManager,
BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder, BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder,
Clock clock) { Clock clock) {
PrivateMessageValidator validator = new PrivateMessageValidator( PrivateMessageValidator validator = new PrivateMessageValidator(
bdfReaderFactory, metadataEncoder, clock); bdfReaderFactory, metadataEncoder, clock);
validationManager.registerMessageValidator( validationManager.registerMessageValidator(CLIENT_ID, validator);
messagingManager.getClientId(),
validator);
return validator; return validator;
} }

View File

@@ -73,8 +73,7 @@ class ConnectionManagerImpl implements ConnectionManager {
ioExecutor.execute(new ManageOutgoingDuplexConnection(c, t, d)); ioExecutor.execute(new ManageOutgoingDuplexConnection(c, t, d));
} }
private byte[] readTag(TransportId t, TransportConnectionReader r) private byte[] readTag(TransportConnectionReader r) throws IOException {
throws IOException {
// Read the tag // Read the tag
byte[] tag = new byte[TAG_LENGTH]; byte[] tag = new byte[TAG_LENGTH];
InputStream in = r.getInputStream(); InputStream in = r.getInputStream();
@@ -128,7 +127,7 @@ class ConnectionManagerImpl implements ConnectionManager {
// Read and recognise the tag // Read and recognise the tag
StreamContext ctx; StreamContext ctx;
try { try {
byte[] tag = readTag(transportId, reader); byte[] tag = readTag(reader);
ctx = keyManager.getStreamContext(transportId, tag); ctx = keyManager.getStreamContext(transportId, tag);
} catch (IOException e) { } catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
@@ -228,7 +227,7 @@ class ConnectionManagerImpl implements ConnectionManager {
// Read and recognise the tag // Read and recognise the tag
StreamContext ctx; StreamContext ctx;
try { try {
byte[] tag = readTag(transportId, reader); byte[] tag = readTag(reader);
ctx = keyManager.getStreamContext(transportId, tag); ctx = keyManager.getStreamContext(transportId, tag);
} catch (IOException e) { } catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
@@ -353,7 +352,7 @@ class ConnectionManagerImpl implements ConnectionManager {
// Read and recognise the tag // Read and recognise the tag
StreamContext ctx; StreamContext ctx;
try { try {
byte[] tag = readTag(transportId, reader); byte[] tag = readTag(reader);
ctx = keyManager.getStreamContext(transportId, tag); ctx = keyManager.getStreamContext(transportId, tag);
} catch (IOException e) { } catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);

View File

@@ -1,8 +1,6 @@
package org.briarproject.plugins; package org.briarproject.plugins;
import org.briarproject.api.Settings;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
@@ -26,7 +24,9 @@ import org.briarproject.api.plugins.simplex.SimplexPlugin;
import org.briarproject.api.plugins.simplex.SimplexPluginCallback; import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
import org.briarproject.api.plugins.simplex.SimplexPluginConfig; import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
import org.briarproject.api.plugins.simplex.SimplexPluginFactory; import org.briarproject.api.plugins.simplex.SimplexPluginFactory;
import org.briarproject.api.property.TransportPropertyManager; import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.api.ui.UiCallback; import org.briarproject.api.ui.UiCallback;

View File

@@ -1,5 +1,9 @@
package org.briarproject.plugins.tcp; package org.briarproject.plugins.tcp;
import org.briarproject.api.TransportId;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.properties.TransportProperties;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@@ -8,10 +12,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
class LanTcpPlugin extends TcpPlugin { class LanTcpPlugin extends TcpPlugin {
static final TransportId ID = new TransportId("lan"); static final TransportId ID = new TransportId("lan");

View File

@@ -1,11 +1,11 @@
package org.briarproject.plugins.tcp; package org.briarproject.plugins.tcp;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.io.IOException; import java.io.IOException;

View File

@@ -1,5 +1,9 @@
package org.briarproject.plugins.tcp; package org.briarproject.plugins.tcp;
import org.briarproject.api.TransportId;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.properties.TransportProperties;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@@ -8,10 +12,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
class WanTcpPlugin extends TcpPlugin { class WanTcpPlugin extends TcpPlugin {
static final TransportId ID = new TransportId("wan"); static final TransportId ID = new TransportId("wan");

View File

@@ -0,0 +1,40 @@
package org.briarproject.properties;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.data.BdfReaderFactory;
import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.api.sync.ValidationManager;
import org.briarproject.api.system.Clock;
import javax.inject.Singleton;
import static org.briarproject.properties.TransportPropertyManagerImpl.CLIENT_ID;
public class PropertiesModule extends AbstractModule {
@Override
protected void configure() {}
@Provides @Singleton
TransportPropertyValidator getValidator(ValidationManager validationManager,
BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder,
Clock clock) {
TransportPropertyValidator validator = new TransportPropertyValidator(
bdfReaderFactory, metadataEncoder, clock);
validationManager.registerMessageValidator(CLIENT_ID, validator);
return validator;
}
@Provides @Singleton
TransportPropertyManager getTransportPropertyManager(
ContactManager contactManager,
TransportPropertyManagerImpl transportPropertyManager) {
contactManager.registerAddContactHook(transportPropertyManager);
contactManager.registerRemoveContactHook(transportPropertyManager);
return transportPropertyManager;
}
}

View File

@@ -0,0 +1,345 @@
package org.briarproject.properties;
import com.google.inject.Inject;
import org.briarproject.api.DeviceId;
import org.briarproject.api.FormatException;
import org.briarproject.api.TransportId;
import org.briarproject.api.UniqueId;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager.AddContactHook;
import org.briarproject.api.contact.ContactManager.RemoveContactHook;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfReader;
import org.briarproject.api.data.BdfReaderFactory;
import org.briarproject.api.data.BdfWriter;
import org.briarproject.api.data.BdfWriterFactory;
import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.data.MetadataParser;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata;
import org.briarproject.api.db.NoSuchSubscriptionException;
import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupFactory;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageFactory;
import org.briarproject.api.sync.MessageId;
import org.briarproject.api.system.Clock;
import org.briarproject.util.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
class TransportPropertyManagerImpl implements TransportPropertyManager,
AddContactHook, RemoveContactHook {
static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
"673ea091673561e28f70122f6a8ea8f4"
+ "97c3624b86fa07f785bb15f09fb87b4b"));
private static final byte[] LOCAL_GROUP_DESCRIPTOR = new byte[0];
private static final Logger LOG =
Logger.getLogger(TransportPropertyManagerImpl.class.getName());
private final DatabaseComponent db;
private final GroupFactory groupFactory;
private final MessageFactory messageFactory;
private final BdfReaderFactory bdfReaderFactory;
private final BdfWriterFactory bdfWriterFactory;
private final MetadataEncoder metadataEncoder;
private final MetadataParser metadataParser;
private final Clock clock;
private final Group localGroup;
/** Ensures isolation between database reads and writes. */
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
@Inject
TransportPropertyManagerImpl(DatabaseComponent db,
GroupFactory groupFactory, MessageFactory messageFactory,
BdfReaderFactory bdfReaderFactory,
BdfWriterFactory bdfWriterFactory, MetadataEncoder metadataEncoder,
MetadataParser metadataParser, Clock clock) {
this.db = db;
this.groupFactory = groupFactory;
this.messageFactory = messageFactory;
this.bdfReaderFactory = bdfReaderFactory;
this.bdfWriterFactory = bdfWriterFactory;
this.metadataEncoder = metadataEncoder;
this.metadataParser = metadataParser;
this.clock = clock;
localGroup = groupFactory.createGroup(CLIENT_ID,
LOCAL_GROUP_DESCRIPTOR);
}
@Override
public void addingContact(ContactId c) {
lock.writeLock().lock();
try {
// Create a group to share with the contact
Group g = getContactGroup(db.getContact(c));
// Subscribe to the group and share it with the contact
db.addGroup(g);
db.addContactGroup(c, g);
db.setVisibility(g.getId(), Collections.singletonList(c));
// Copy the latest local properties into the group
DeviceId dev = db.getDeviceId();
Map<TransportId, TransportProperties> local = getLocalProperties();
for (Entry<TransportId, TransportProperties> e : local.entrySet())
storeMessage(g.getId(), dev, e.getKey(), e.getValue(), 0);
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} catch (FormatException e) {
throw new RuntimeException(e);
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
lock.writeLock().unlock();
}
}
private Group getContactGroup(Contact c) {
AuthorId local = c.getLocalAuthorId();
AuthorId remote = c.getAuthor().getId();
byte[] descriptor = encodeGroupDescriptor(local, remote);
return groupFactory.createGroup(CLIENT_ID, descriptor);
}
private byte[] encodeGroupDescriptor(AuthorId local, AuthorId remote) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
BdfWriter w = bdfWriterFactory.createWriter(out);
try {
w.writeListStart();
if (UniqueId.IdComparator.INSTANCE.compare(local, remote) < 0) {
w.writeRaw(local.getBytes());
w.writeRaw(remote.getBytes());
} else {
w.writeRaw(remote.getBytes());
w.writeRaw(local.getBytes());
}
w.writeListEnd();
} catch (IOException e) {
// Shouldn't happen with ByteArrayOutputStream
throw new RuntimeException(e);
}
return out.toByteArray();
}
private void storeMessage(GroupId g, DeviceId dev, TransportId t,
TransportProperties p, long version) throws DbException,
IOException {
byte[] body = encodeProperties(dev, t, p, version);
long now = clock.currentTimeMillis();
Message m = messageFactory.createMessage(g, now, body);
BdfDictionary d = new BdfDictionary();
d.put("transportId", t.getString());
d.put("version", version);
d.put("local", true);
db.addLocalMessage(m, CLIENT_ID, metadataEncoder.encode(d));
}
private byte[] encodeProperties(DeviceId dev, TransportId t,
TransportProperties p, long version) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
BdfWriter w = bdfWriterFactory.createWriter(out);
try {
w.writeListStart();
w.writeRaw(dev.getBytes());
w.writeString(t.getString());
w.writeInteger(version);
w.writeDictionary(p);
w.writeListEnd();
} catch (IOException e) {
// Shouldn't happen with ByteArrayOutputStream
throw new RuntimeException(e);
}
return out.toByteArray();
}
@Override
public void removingContact(ContactId c) {
lock.writeLock().lock();
try {
db.removeGroup(getContactGroup(db.getContact(c)));
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
lock.writeLock().unlock();
}
}
@Override
public Map<TransportId, TransportProperties> getLocalProperties()
throws DbException {
lock.readLock().lock();
try {
// Find the latest local version for each transport
Map<TransportId, LatestUpdate> latest =
findLatest(localGroup.getId(), true);
// Retrieve and decode the latest local properties
Map<TransportId, TransportProperties> local =
new HashMap<TransportId, TransportProperties>();
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
byte[] raw = db.getRawMessage(e.getValue().messageId);
local.put(e.getKey(), decodeProperties(raw));
}
return Collections.unmodifiableMap(local);
} catch (NoSuchSubscriptionException e) {
// Local group doesn't exist - there are no local properties
return Collections.emptyMap();
} catch (IOException e) {
throw new DbException(e);
} finally {
lock.readLock().unlock();
}
}
private Map<TransportId, LatestUpdate> findLatest(GroupId g, boolean local)
throws DbException, FormatException {
// TODO: Use metadata queries
Map<TransportId, LatestUpdate> latestUpdates =
new HashMap<TransportId, LatestUpdate>();
Map<MessageId, Metadata> metadata = db.getMessageMetadata(g);
for (Entry<MessageId, Metadata> e : metadata.entrySet()) {
BdfDictionary d = metadataParser.parse(e.getValue());
if (d.getBoolean("local") != local) continue;
TransportId t = new TransportId(d.getString("transportId"));
long version = d.getInteger("version");
LatestUpdate latest = latestUpdates.get(t);
if (latest == null || version > latest.version)
latestUpdates.put(t, new LatestUpdate(e.getKey(), version));
}
return latestUpdates;
}
private TransportProperties decodeProperties(byte[] raw)
throws IOException {
TransportProperties p = new TransportProperties();
ByteArrayInputStream in = new ByteArrayInputStream(raw,
MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH);
BdfReader r = bdfReaderFactory.createReader(in);
r.readListStart();
r.skipRaw(); // Device ID
r.skipString(); // Transport ID
r.skipInteger(); // Version
r.readDictionaryStart();
while (!r.hasDictionaryEnd()) {
String key = r.readString(MAX_PROPERTY_LENGTH);
String value = r.readString(MAX_PROPERTY_LENGTH);
p.put(key, value);
}
return p;
}
@Override
public TransportProperties getLocalProperties(TransportId t)
throws DbException {
lock.readLock().lock();
try {
// Find the latest local version
LatestUpdate latest = findLatest(localGroup.getId(), true).get(t);
if (latest == null) return null;
// Retrieve and decode the latest local properties
return decodeProperties(db.getRawMessage(latest.messageId));
} catch (NoSuchSubscriptionException e) {
// Local group doesn't exist - there are no local properties
return null;
} catch (IOException e) {
throw new DbException(e);
} finally {
lock.readLock().unlock();
}
}
@Override
public Map<ContactId, TransportProperties> getRemoteProperties(
TransportId t) throws DbException {
lock.readLock().lock();
try {
Map<ContactId, TransportProperties> remote =
new HashMap<ContactId, TransportProperties>();
for (Contact c : db.getContacts()) {
Group g = getContactGroup(c);
// Find the latest remote version
LatestUpdate latest = findLatest(g.getId(), false).get(t);
if (latest != null) {
// Retrieve and decode the latest remote properties
byte[] raw = db.getRawMessage(latest.messageId);
remote.put(c.getId(), decodeProperties(raw));
}
}
return Collections.unmodifiableMap(remote);
} catch (IOException e) {
throw new DbException(e);
} finally {
lock.readLock().unlock();
}
}
@Override
public void mergeLocalProperties(TransportId t, TransportProperties p)
throws DbException {
lock.writeLock().lock();
try {
// Create the local group if necessary
db.addGroup(localGroup);
// Merge the new properties with any existing properties
TransportProperties merged;
LatestUpdate latest = findLatest(localGroup.getId(), true).get(t);
if (latest == null) {
merged = p;
} else {
byte[] raw = db.getRawMessage(latest.messageId);
TransportProperties old = decodeProperties(raw);
merged = new TransportProperties(old);
merged.putAll(p);
if (merged.equals(old)) return; // Unchanged
}
// Store the merged properties in the local group
DeviceId dev = db.getDeviceId();
long version = latest == null ? 0 : latest.version + 1;
storeMessage(localGroup.getId(), dev, t, merged, version);
// Store the merged properties in each contact's group
for (Contact c : db.getContacts()) {
Group g = getContactGroup(c);
latest = findLatest(g.getId(), true).get(t);
version = latest == null ? 0 : latest.version + 1;
storeMessage(g.getId(), dev, t, merged, version);
}
} catch (IOException e) {
throw new DbException(e);
} finally {
lock.writeLock().unlock();
}
}
private static class LatestUpdate {
private final MessageId messageId;
private final long version;
private LatestUpdate(MessageId messageId, long version) {
this.messageId = messageId;
this.version = version;
}
}
}

View File

@@ -0,0 +1,85 @@
package org.briarproject.properties;
import org.briarproject.api.FormatException;
import org.briarproject.api.UniqueId;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfReader;
import org.briarproject.api.data.BdfReaderFactory;
import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.db.Metadata;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageValidator;
import org.briarproject.api.system.Clock;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.logging.Logger;
import javax.inject.Inject;
import static org.briarproject.api.TransportId.MAX_TRANSPORT_ID_LENGTH;
import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
class TransportPropertyValidator implements MessageValidator {
private static final Logger LOG =
Logger.getLogger(TransportPropertyValidator.class.getName());
private final BdfReaderFactory bdfReaderFactory;
private final MetadataEncoder metadataEncoder;
private final Clock clock;
@Inject
TransportPropertyValidator(BdfReaderFactory bdfReaderFactory,
MetadataEncoder metadataEncoder, Clock clock) {
this.bdfReaderFactory = bdfReaderFactory;
this.metadataEncoder = metadataEncoder;
this.clock = clock;
}
@Override
public Metadata validateMessage(Message m) {
// Reject the message if it's too far in the future
long now = clock.currentTimeMillis();
if (m.getTimestamp() - now > MAX_CLOCK_DIFFERENCE) {
LOG.info("Timestamp is too far in the future");
return null;
}
try {
// Parse the message body
byte[] raw = m.getRaw();
ByteArrayInputStream in = new ByteArrayInputStream(raw,
MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH);
BdfReader r = bdfReaderFactory.createReader(in);
r.readListStart();
byte[] deviceId = r.readRaw(UniqueId.LENGTH);
if (deviceId.length != UniqueId.LENGTH) throw new FormatException();
String transportId = r.readString(MAX_TRANSPORT_ID_LENGTH);
if (transportId.length() == 0) throw new FormatException();
long version = r.readInteger();
if (version < 0) throw new FormatException();
r.readDictionaryStart();
for (int i = 0; !r.hasDictionaryEnd(); i++) {
if (i == MAX_PROPERTIES_PER_TRANSPORT)
throw new FormatException();
r.readString(MAX_PROPERTY_LENGTH);
r.readString(MAX_PROPERTY_LENGTH);
}
r.readDictionaryEnd();
r.readListEnd();
if (!r.eof()) throw new FormatException();
// Return the metadata
BdfDictionary d = new BdfDictionary();
d.put("transportId", transportId);
d.put("version", version);
d.put("local", false);
return metadataEncoder.encode(d);
} catch (IOException e) {
LOG.info("Invalid transport update");
return null;
}
}
}

View File

@@ -1,14 +0,0 @@
package org.briarproject.property;
import com.google.inject.AbstractModule;
import org.briarproject.api.property.TransportPropertyManager;
public class PropertyModule extends AbstractModule {
@Override
protected void configure() {
bind(TransportPropertyManager.class).to(
TransportPropertyManagerImpl.class);
}
}

View File

@@ -1,53 +0,0 @@
package org.briarproject.property;
import com.google.inject.Inject;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.property.TransportPropertyManager;
import java.util.Map;
// Temporary facade during sync protocol refactoring
class TransportPropertyManagerImpl implements TransportPropertyManager {
private final DatabaseComponent db;
@Inject
TransportPropertyManagerImpl(DatabaseComponent db) {
this.db = db;
}
@Override
public Map<TransportId, TransportProperties> getLocalProperties()
throws DbException {
return db.getLocalProperties();
}
@Override
public TransportProperties getLocalProperties(TransportId t)
throws DbException {
return db.getLocalProperties(t);
}
@Override
public Map<ContactId, TransportProperties> getRemoteProperties(
TransportId t) throws DbException {
return db.getRemoteProperties(t);
}
@Override
public void mergeLocalProperties(TransportId t, TransportProperties p)
throws DbException {
db.mergeLocalProperties(t, p);
}
@Override
public void setRemoteProperties(ContactId c,
Map<TransportId, TransportProperties> p) throws DbException {
db.setRemoteProperties(c, p);
}
}

View File

@@ -2,9 +2,9 @@ package org.briarproject.settings;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.briarproject.api.Settings;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.settings.SettingsManager; import org.briarproject.api.settings.SettingsManager;
class SettingsManagerImpl implements SettingsManager { class SettingsManagerImpl implements SettingsManager {

View File

@@ -9,13 +9,11 @@ import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener; import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent; import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
import org.briarproject.api.event.LocalTransportsUpdatedEvent;
import org.briarproject.api.event.MessageRequestedEvent; import org.briarproject.api.event.MessageRequestedEvent;
import org.briarproject.api.event.MessageToAckEvent; import org.briarproject.api.event.MessageToAckEvent;
import org.briarproject.api.event.MessageToRequestEvent; import org.briarproject.api.event.MessageToRequestEvent;
import org.briarproject.api.event.MessageValidatedEvent; import org.briarproject.api.event.MessageValidatedEvent;
import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent; import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent;
import org.briarproject.api.event.RemoteTransportsUpdatedEvent;
import org.briarproject.api.event.ShutdownEvent; import org.briarproject.api.event.ShutdownEvent;
import org.briarproject.api.event.TransportRemovedEvent; import org.briarproject.api.event.TransportRemovedEvent;
import org.briarproject.api.sync.Ack; import org.briarproject.api.sync.Ack;
@@ -25,8 +23,6 @@ import org.briarproject.api.sync.Request;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.SyncSession; import org.briarproject.api.sync.SyncSession;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import java.io.IOException; import java.io.IOException;
@@ -91,8 +87,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
eventBus.addListener(this); eventBus.addListener(this);
try { try {
// Start a query for each type of packet, in order of urgency // Start a query for each type of packet, in order of urgency
dbExecutor.execute(new GenerateTransportAcks());
dbExecutor.execute(new GenerateTransportUpdates());
dbExecutor.execute(new GenerateSubscriptionAck()); dbExecutor.execute(new GenerateSubscriptionAck());
dbExecutor.execute(new GenerateSubscriptionUpdate()); dbExecutor.execute(new GenerateSubscriptionUpdate());
dbExecutor.execute(new GenerateAck()); dbExecutor.execute(new GenerateAck());
@@ -123,7 +117,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
now = clock.currentTimeMillis(); now = clock.currentTimeMillis();
if (now >= nextRetxQuery) { if (now >= nextRetxQuery) {
// Check for retransmittable packets // Check for retransmittable packets
dbExecutor.execute(new GenerateTransportUpdates());
dbExecutor.execute(new GenerateSubscriptionUpdate()); dbExecutor.execute(new GenerateSubscriptionUpdate());
dbExecutor.execute(new GenerateBatch()); dbExecutor.execute(new GenerateBatch());
dbExecutor.execute(new GenerateOffer()); dbExecutor.execute(new GenerateOffer());
@@ -171,8 +164,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
dbExecutor.execute(new GenerateSubscriptionUpdate()); dbExecutor.execute(new GenerateSubscriptionUpdate());
dbExecutor.execute(new GenerateOffer()); dbExecutor.execute(new GenerateOffer());
} }
} else if (e instanceof LocalTransportsUpdatedEvent) {
dbExecutor.execute(new GenerateTransportUpdates());
} else if (e instanceof MessageRequestedEvent) { } else if (e instanceof MessageRequestedEvent) {
if (((MessageRequestedEvent) e).getContactId().equals(contactId)) if (((MessageRequestedEvent) e).getContactId().equals(contactId))
dbExecutor.execute(new GenerateBatch()); dbExecutor.execute(new GenerateBatch());
@@ -189,11 +180,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
dbExecutor.execute(new GenerateSubscriptionAck()); dbExecutor.execute(new GenerateSubscriptionAck());
dbExecutor.execute(new GenerateOffer()); dbExecutor.execute(new GenerateOffer());
} }
} else if (e instanceof RemoteTransportsUpdatedEvent) {
RemoteTransportsUpdatedEvent r =
(RemoteTransportsUpdatedEvent) e;
if (r.getContactId().equals(contactId))
dbExecutor.execute(new GenerateTransportAcks());
} else if (e instanceof ShutdownEvent) { } else if (e instanceof ShutdownEvent) {
interrupt(); interrupt();
} else if (e instanceof TransportRemovedEvent) { } else if (e instanceof TransportRemovedEvent) {
@@ -414,76 +400,4 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
dbExecutor.execute(new GenerateSubscriptionUpdate()); dbExecutor.execute(new GenerateSubscriptionUpdate());
} }
} }
// This task runs on the database thread
private class GenerateTransportAcks implements Runnable {
public void run() {
if (interrupted) return;
try {
Collection<TransportAck> acks =
db.generateTransportAcks(contactId);
if (LOG.isLoggable(INFO))
LOG.info("Generated transport acks: " + (acks != null));
if (acks != null) writerTasks.add(new WriteTransportAcks(acks));
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
}
// This tasks runs on the writer thread
private class WriteTransportAcks implements ThrowingRunnable<IOException> {
private final Collection<TransportAck> acks;
private WriteTransportAcks(Collection<TransportAck> acks) {
this.acks = acks;
}
public void run() throws IOException {
if (interrupted) return;
for (TransportAck a : acks) packetWriter.writeTransportAck(a);
LOG.info("Sent transport acks");
dbExecutor.execute(new GenerateTransportAcks());
}
}
// This task runs on the database thread
private class GenerateTransportUpdates implements Runnable {
public void run() {
if (interrupted) return;
try {
Collection<TransportUpdate> t =
db.generateTransportUpdates(contactId, maxLatency);
if (LOG.isLoggable(INFO))
LOG.info("Generated transport updates: " + (t != null));
if (t != null) writerTasks.add(new WriteTransportUpdates(t));
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
}
// This task runs on the writer thread
private class WriteTransportUpdates
implements ThrowingRunnable<IOException> {
private final Collection<TransportUpdate> updates;
private WriteTransportUpdates(Collection<TransportUpdate> updates) {
this.updates = updates;
}
public void run() throws IOException {
if (interrupted) return;
for (TransportUpdate u : updates)
packetWriter.writeTransportUpdate(u);
LOG.info("Sent transport updates");
dbExecutor.execute(new GenerateTransportUpdates());
}
}
} }

View File

@@ -19,8 +19,6 @@ import org.briarproject.api.sync.Request;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.SyncSession; import org.briarproject.api.sync.SyncSession;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -77,12 +75,6 @@ class IncomingSession implements SyncSession, EventListener {
} else if (packetReader.hasSubscriptionUpdate()) { } else if (packetReader.hasSubscriptionUpdate()) {
SubscriptionUpdate u = packetReader.readSubscriptionUpdate(); SubscriptionUpdate u = packetReader.readSubscriptionUpdate();
dbExecutor.execute(new ReceiveSubscriptionUpdate(u)); dbExecutor.execute(new ReceiveSubscriptionUpdate(u));
} else if (packetReader.hasTransportAck()) {
TransportAck a = packetReader.readTransportAck();
dbExecutor.execute(new ReceiveTransportAck(a));
} else if (packetReader.hasTransportUpdate()) {
TransportUpdate u = packetReader.readTransportUpdate();
dbExecutor.execute(new ReceiveTransportUpdate(u));
} else { } else {
throw new FormatException(); throw new FormatException();
} }
@@ -216,40 +208,4 @@ class IncomingSession implements SyncSession, EventListener {
} }
} }
} }
private class ReceiveTransportAck implements Runnable {
private final TransportAck ack;
private ReceiveTransportAck(TransportAck ack) {
this.ack = ack;
}
public void run() {
try {
db.receiveTransportAck(contactId, ack);
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
}
private class ReceiveTransportUpdate implements Runnable {
private final TransportUpdate update;
private ReceiveTransportUpdate(TransportUpdate update) {
this.update = update;
}
public void run() {
try {
db.receiveTransportUpdate(contactId, update);
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
}
} }

View File

@@ -1,8 +1,6 @@
package org.briarproject.sync; package org.briarproject.sync;
import org.briarproject.api.FormatException; import org.briarproject.api.FormatException;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.UniqueId; import org.briarproject.api.UniqueId;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.data.BdfReader; import org.briarproject.api.data.BdfReader;
@@ -17,8 +15,6 @@ import org.briarproject.api.sync.PacketReader;
import org.briarproject.api.sync.Request; import org.briarproject.api.sync.Request;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.util.ByteUtils; import org.briarproject.util.ByteUtils;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@@ -26,21 +22,14 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.api.TransportPropertyConstants.MAX_TRANSPORT_ID_LENGTH;
import static org.briarproject.api.sync.PacketTypes.ACK; import static org.briarproject.api.sync.PacketTypes.ACK;
import static org.briarproject.api.sync.PacketTypes.MESSAGE; import static org.briarproject.api.sync.PacketTypes.MESSAGE;
import static org.briarproject.api.sync.PacketTypes.OFFER; import static org.briarproject.api.sync.PacketTypes.OFFER;
import static org.briarproject.api.sync.PacketTypes.REQUEST; import static org.briarproject.api.sync.PacketTypes.REQUEST;
import static org.briarproject.api.sync.PacketTypes.SUBSCRIPTION_ACK; import static org.briarproject.api.sync.PacketTypes.SUBSCRIPTION_ACK;
import static org.briarproject.api.sync.PacketTypes.SUBSCRIPTION_UPDATE; import static org.briarproject.api.sync.PacketTypes.SUBSCRIPTION_UPDATE;
import static org.briarproject.api.sync.PacketTypes.TRANSPORT_ACK;
import static org.briarproject.api.sync.PacketTypes.TRANSPORT_UPDATE;
import static org.briarproject.api.sync.SyncConstants.MAX_PACKET_PAYLOAD_LENGTH; import static org.briarproject.api.sync.SyncConstants.MAX_PACKET_PAYLOAD_LENGTH;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.api.sync.SyncConstants.PACKET_HEADER_LENGTH; import static org.briarproject.api.sync.SyncConstants.PACKET_HEADER_LENGTH;
@@ -205,66 +194,4 @@ class PacketReaderImpl implements PacketReader {
state = State.BUFFER_EMPTY; state = State.BUFFER_EMPTY;
return u; return u;
} }
public boolean hasTransportAck() throws IOException {
return !eof() && header[1] == TRANSPORT_ACK;
}
public TransportAck readTransportAck() throws IOException {
if (!hasTransportAck()) throw new FormatException();
// Set up the reader
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
BdfReader r = bdfReaderFactory.createReader(bais);
// Read the start of the payload
r.readListStart();
// Read the transport ID and version
String idString = r.readString(MAX_TRANSPORT_ID_LENGTH);
if (idString.length() == 0) throw new FormatException();
TransportId id = new TransportId(idString);
long version = r.readInteger();
if (version < 0) throw new FormatException();
// Read the end of the payload
r.readListEnd();
if (!r.eof()) throw new FormatException();
state = State.BUFFER_EMPTY;
// Build and return the transport ack
return new TransportAck(id, version);
}
public boolean hasTransportUpdate() throws IOException {
return !eof() && header[1] == TRANSPORT_UPDATE;
}
public TransportUpdate readTransportUpdate() throws IOException {
if (!hasTransportUpdate()) throw new FormatException();
// Set up the reader
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
BdfReader r = bdfReaderFactory.createReader(bais);
// Read the start of the payload
r.readListStart();
// Read the transport ID
String idString = r.readString(MAX_TRANSPORT_ID_LENGTH);
if (idString.length() == 0) throw new FormatException();
TransportId id = new TransportId(idString);
// Read the transport properties
Map<String, String> p = new HashMap<String, String>();
r.readDictionaryStart();
for (int i = 0; !r.hasDictionaryEnd(); i++) {
if (i == MAX_PROPERTIES_PER_TRANSPORT)
throw new FormatException();
String key = r.readString(MAX_PROPERTY_LENGTH);
String value = r.readString(MAX_PROPERTY_LENGTH);
p.put(key, value);
}
r.readDictionaryEnd();
// Read the version number
long version = r.readInteger();
if (version < 0) throw new FormatException();
// Read the end of the payload
r.readListEnd();
if (!r.eof()) throw new FormatException();
state = State.BUFFER_EMPTY;
// Build and return the transport update
return new TransportUpdate(id, new TransportProperties(p), version);
}
} }

View File

@@ -12,8 +12,6 @@ import org.briarproject.api.sync.PacketWriter;
import org.briarproject.api.sync.Request; import org.briarproject.api.sync.Request;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.util.ByteUtils; import org.briarproject.util.ByteUtils;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -25,8 +23,6 @@ import static org.briarproject.api.sync.PacketTypes.OFFER;
import static org.briarproject.api.sync.PacketTypes.REQUEST; import static org.briarproject.api.sync.PacketTypes.REQUEST;
import static org.briarproject.api.sync.PacketTypes.SUBSCRIPTION_ACK; import static org.briarproject.api.sync.PacketTypes.SUBSCRIPTION_ACK;
import static org.briarproject.api.sync.PacketTypes.SUBSCRIPTION_UPDATE; import static org.briarproject.api.sync.PacketTypes.SUBSCRIPTION_UPDATE;
import static org.briarproject.api.sync.PacketTypes.TRANSPORT_ACK;
import static org.briarproject.api.sync.PacketTypes.TRANSPORT_UPDATE;
import static org.briarproject.api.sync.SyncConstants.MAX_PACKET_PAYLOAD_LENGTH; import static org.briarproject.api.sync.SyncConstants.MAX_PACKET_PAYLOAD_LENGTH;
import static org.briarproject.api.sync.SyncConstants.PACKET_HEADER_LENGTH; import static org.briarproject.api.sync.SyncConstants.PACKET_HEADER_LENGTH;
import static org.briarproject.api.sync.SyncConstants.PROTOCOL_VERSION; import static org.briarproject.api.sync.SyncConstants.PROTOCOL_VERSION;
@@ -125,27 +121,6 @@ class PacketWriterImpl implements PacketWriter {
writePacket(SUBSCRIPTION_UPDATE); writePacket(SUBSCRIPTION_UPDATE);
} }
public void writeTransportAck(TransportAck a) throws IOException {
if (payload.size() != 0) throw new IllegalStateException();
BdfWriter w = bdfWriterFactory.createWriter(payload);
w.writeListStart();
w.writeString(a.getId().getString());
w.writeInteger(a.getVersion());
w.writeListEnd();
writePacket(TRANSPORT_ACK);
}
public void writeTransportUpdate(TransportUpdate u) throws IOException {
if (payload.size() != 0) throw new IllegalStateException();
BdfWriter w = bdfWriterFactory.createWriter(payload);
w.writeListStart();
w.writeString(u.getId().getString());
w.writeDictionary(u.getProperties());
w.writeInteger(u.getVersion());
w.writeListEnd();
writePacket(TRANSPORT_UPDATE);
}
public void flush() throws IOException { public void flush() throws IOException {
out.flush(); out.flush();
} }

View File

@@ -15,8 +15,6 @@ import org.briarproject.api.sync.PacketWriter;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.SyncSession; import org.briarproject.api.sync.SyncSession;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
@@ -68,7 +66,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
this.transportId = transportId; this.transportId = transportId;
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
this.packetWriter = packetWriter; this.packetWriter = packetWriter;
outstandingQueries = new AtomicInteger(6); // One per type of packet outstandingQueries = new AtomicInteger(4); // One per type of packet
writerTasks = new LinkedBlockingQueue<ThrowingRunnable<IOException>>(); writerTasks = new LinkedBlockingQueue<ThrowingRunnable<IOException>>();
} }
@@ -76,8 +74,6 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
eventBus.addListener(this); eventBus.addListener(this);
try { try {
// Start a query for each type of packet, in order of urgency // Start a query for each type of packet, in order of urgency
dbExecutor.execute(new GenerateTransportAcks());
dbExecutor.execute(new GenerateTransportUpdates());
dbExecutor.execute(new GenerateSubscriptionAck()); dbExecutor.execute(new GenerateSubscriptionAck());
dbExecutor.execute(new GenerateSubscriptionUpdate()); dbExecutor.execute(new GenerateSubscriptionUpdate());
dbExecutor.execute(new GenerateAck()); dbExecutor.execute(new GenerateAck());
@@ -264,78 +260,4 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
dbExecutor.execute(new GenerateSubscriptionUpdate()); dbExecutor.execute(new GenerateSubscriptionUpdate());
} }
} }
// This task runs on the database thread
private class GenerateTransportAcks implements Runnable {
public void run() {
if (interrupted) return;
try {
Collection<TransportAck> acks =
db.generateTransportAcks(contactId);
if (LOG.isLoggable(INFO))
LOG.info("Generated transport acks: " + (acks != null));
if (acks == null) decrementOutstandingQueries();
else writerTasks.add(new WriteTransportAcks(acks));
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
}
// This tasks runs on the writer thread
private class WriteTransportAcks implements ThrowingRunnable<IOException> {
private final Collection<TransportAck> acks;
private WriteTransportAcks(Collection<TransportAck> acks) {
this.acks = acks;
}
public void run() throws IOException {
if (interrupted) return;
for (TransportAck a : acks) packetWriter.writeTransportAck(a);
LOG.info("Sent transport acks");
dbExecutor.execute(new GenerateTransportAcks());
}
}
// This task runs on the database thread
private class GenerateTransportUpdates implements Runnable {
public void run() {
if (interrupted) return;
try {
Collection<TransportUpdate> t =
db.generateTransportUpdates(contactId, maxLatency);
if (LOG.isLoggable(INFO))
LOG.info("Generated transport updates: " + (t != null));
if (t == null) decrementOutstandingQueries();
else writerTasks.add(new WriteTransportUpdates(t));
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
}
// This task runs on the writer thread
private class WriteTransportUpdates
implements ThrowingRunnable<IOException> {
private final Collection<TransportUpdate> updates;
private WriteTransportUpdates(Collection<TransportUpdate> updates) {
this.updates = updates;
}
public void run() throws IOException {
if (interrupted) return;
for (TransportUpdate u : updates)
packetWriter.writeTransportUpdate(u);
LOG.info("Sent transport updates");
dbExecutor.execute(new GenerateTransportUpdates());
}
}
} }

View File

@@ -18,7 +18,6 @@ import org.briarproject.api.system.Timer;
import org.briarproject.api.transport.KeyManager; import org.briarproject.api.transport.KeyManager;
import org.briarproject.api.transport.StreamContext; import org.briarproject.api.transport.StreamContext;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -71,12 +70,10 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
return true; return true;
} }
public void addContact(ContactId c, Collection<TransportId> transports, public void addContact(ContactId c, SecretKey master, long timestamp,
SecretKey master, long timestamp, boolean alice) { boolean alice) {
for (TransportId t : transports) { for (TransportKeyManager m : managers.values())
TransportKeyManager m = managers.get(t); m.addContact(c, master, timestamp, alice);
if (m != null) m.addContact(c, master, timestamp, alice);
}
} }
public StreamContext getStreamContext(ContactId c, TransportId t) { public StreamContext getStreamContext(ContactId c, TransportId t) {

View File

@@ -65,7 +65,8 @@ public class StringUtils {
/** Converts the given hex string to a byte array. */ /** Converts the given hex string to a byte array. */
public static byte[] fromHexString(String hex) { public static byte[] fromHexString(String hex) {
int len = hex.length(); int len = hex.length();
if (len % 2 != 0) throw new IllegalArgumentException("Not a hex string"); if (len % 2 != 0)
throw new IllegalArgumentException("Not a hex string");
byte[] bytes = new byte[len / 2]; byte[] bytes = new byte[len / 2];
for (int i = 0, j = 0; i < len; i += 2, j++) { for (int i = 0, j = 0; i < len; i += 2, j++) {
int high = hexDigitToInt(hex.charAt(i)); int high = hexDigitToInt(hex.charAt(i));

View File

@@ -1,12 +1,12 @@
package org.briarproject.plugins.bluetooth; package org.briarproject.plugins.bluetooth;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.util.LatchedReference; import org.briarproject.util.LatchedReference;
import org.briarproject.util.OsUtils; import org.briarproject.util.OsUtils;

View File

@@ -1,7 +1,6 @@
package org.briarproject.plugins.modem; package org.briarproject.plugins.modem;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.plugins.TransportConnectionReader; import org.briarproject.api.plugins.TransportConnectionReader;
@@ -9,6 +8,7 @@ import org.briarproject.api.plugins.TransportConnectionWriter;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.io.IOException; import java.io.IOException;

View File

@@ -4,7 +4,6 @@ import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.sync.Ack; import org.briarproject.api.sync.Ack;
@@ -21,7 +20,6 @@ import org.briarproject.api.sync.PacketWriter;
import org.briarproject.api.sync.PacketWriterFactory; import org.briarproject.api.sync.PacketWriterFactory;
import org.briarproject.api.sync.Request; import org.briarproject.api.sync.Request;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.api.transport.StreamContext; import org.briarproject.api.transport.StreamContext;
import org.briarproject.api.transport.StreamReaderFactory; import org.briarproject.api.transport.StreamReaderFactory;
import org.briarproject.api.transport.StreamWriterFactory; import org.briarproject.api.transport.StreamWriterFactory;
@@ -56,12 +54,11 @@ public class ProtocolIntegrationTest extends BriarTestCase {
private final PacketWriterFactory packetWriterFactory; private final PacketWriterFactory packetWriterFactory;
private final ContactId contactId; private final ContactId contactId;
private final TransportId transportId;
private final SecretKey tagKey, headerKey; private final SecretKey tagKey, headerKey;
private final Group group; private final Group group;
private final Message message, message1; private final Message message, message1;
private final Collection<MessageId> messageIds; private final Collection<MessageId> messageIds;
private final TransportId transportId;
private final TransportProperties transportProperties;
public ProtocolIntegrationTest() throws Exception { public ProtocolIntegrationTest() throws Exception {
Injector i = Guice.createInjector(new TestDatabaseModule(), Injector i = Guice.createInjector(new TestDatabaseModule(),
@@ -74,6 +71,7 @@ public class ProtocolIntegrationTest extends BriarTestCase {
packetReaderFactory = i.getInstance(PacketReaderFactory.class); packetReaderFactory = i.getInstance(PacketReaderFactory.class);
packetWriterFactory = i.getInstance(PacketWriterFactory.class); packetWriterFactory = i.getInstance(PacketWriterFactory.class);
contactId = new ContactId(234); contactId = new ContactId(234);
transportId = new TransportId("id");
// Create the transport keys // Create the transport keys
tagKey = TestUtils.createSecretKey(); tagKey = TestUtils.createSecretKey();
headerKey = TestUtils.createSecretKey(); headerKey = TestUtils.createSecretKey();
@@ -91,10 +89,6 @@ public class ProtocolIntegrationTest extends BriarTestCase {
message1 = messageFactory.createMessage(group.getId(), timestamp, message1 = messageFactory.createMessage(group.getId(), timestamp,
messageBody.getBytes("UTF-8")); messageBody.getBytes("UTF-8"));
messageIds = Arrays.asList(message.getId(), message1.getId()); messageIds = Arrays.asList(message.getId(), message1.getId());
// Create some transport properties
transportId = new TransportId("id");
transportProperties = new TransportProperties(Collections.singletonMap(
"bar", "baz"));
} }
@Test @Test
@@ -124,10 +118,6 @@ public class ProtocolIntegrationTest extends BriarTestCase {
Collections.singletonList(group), 1); Collections.singletonList(group), 1);
packetWriter.writeSubscriptionUpdate(su); packetWriter.writeSubscriptionUpdate(su);
TransportUpdate tu = new TransportUpdate(transportId,
transportProperties, 1);
packetWriter.writeTransportUpdate(tu);
streamWriter.flush(); streamWriter.flush();
return out.toByteArray(); return out.toByteArray();
} }
@@ -174,13 +164,6 @@ public class ProtocolIntegrationTest extends BriarTestCase {
assertEquals(Collections.singletonList(group), su.getGroups()); assertEquals(Collections.singletonList(group), su.getGroups());
assertEquals(1, su.getVersion()); assertEquals(1, su.getVersion());
// Read the transport update
assertTrue(packetReader.hasTransportUpdate());
TransportUpdate tu = packetReader.readTransportUpdate();
assertEquals(transportId, tu.getId());
assertEquals(transportProperties, tu.getProperties());
assertEquals(1, tu.getVersion());
in.close(); in.close();
} }

View File

@@ -3,7 +3,6 @@ package org.briarproject.db;
import org.briarproject.BriarTestCase; import org.briarproject.BriarTestCase;
import org.briarproject.TestUtils; import org.briarproject.TestUtils;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
@@ -18,7 +17,6 @@ import org.briarproject.api.db.NoSuchTransportException;
import org.briarproject.api.db.StorageStatus; import org.briarproject.api.db.StorageStatus;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent; import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
import org.briarproject.api.event.LocalTransportsUpdatedEvent;
import org.briarproject.api.event.MessageAddedEvent; import org.briarproject.api.event.MessageAddedEvent;
import org.briarproject.api.event.MessageRequestedEvent; import org.briarproject.api.event.MessageRequestedEvent;
import org.briarproject.api.event.MessageToAckEvent; import org.briarproject.api.event.MessageToAckEvent;
@@ -42,8 +40,6 @@ import org.briarproject.api.sync.Offer;
import org.briarproject.api.sync.Request; import org.briarproject.api.sync.Request;
import org.briarproject.api.sync.SubscriptionAck; import org.briarproject.api.sync.SubscriptionAck;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.TransportAck;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.api.transport.IncomingKeys; import org.briarproject.api.transport.IncomingKeys;
import org.briarproject.api.transport.OutgoingKeys; import org.briarproject.api.transport.OutgoingKeys;
import org.briarproject.api.transport.TransportKeys; import org.briarproject.api.transport.TransportKeys;
@@ -60,7 +56,6 @@ import static org.briarproject.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGT
import static org.briarproject.db.DatabaseConstants.MAX_OFFERED_MESSAGES; import static org.briarproject.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@@ -80,7 +75,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
private final Message message; private final Message message;
private final Metadata metadata; private final Metadata metadata;
private final TransportId transportId; private final TransportId transportId;
private final TransportProperties transportProperties;
private final int maxLatency; private final int maxLatency;
private final ContactId contactId; private final ContactId contactId;
private final Contact contact; private final Contact contact;
@@ -88,7 +82,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
public DatabaseComponentImplTest() { public DatabaseComponentImplTest() {
clientId = new ClientId(TestUtils.getRandomId()); clientId = new ClientId(TestUtils.getRandomId());
groupId = new GroupId(TestUtils.getRandomId()); groupId = new GroupId(TestUtils.getRandomId());
ClientId clientId = new ClientId(TestUtils.getRandomId());
byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH]; byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
group = new Group(groupId, clientId, descriptor); group = new Group(groupId, clientId, descriptor);
authorId = new AuthorId(TestUtils.getRandomId()); authorId = new AuthorId(TestUtils.getRandomId());
@@ -106,8 +99,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
metadata = new Metadata(); metadata = new Metadata();
metadata.put("foo", new byte[] {'b', 'a', 'r'}); metadata.put("foo", new byte[] {'b', 'a', 'r'});
transportId = new TransportId("id"); transportId = new TransportId("id");
transportProperties = new TransportProperties(Collections.singletonMap(
"bar", "baz"));
maxLatency = Integer.MAX_VALUE; maxLatency = Integer.MAX_VALUE;
contactId = new ContactId(234); contactId = new ContactId(234);
contact = new Contact(contactId, author, localAuthorId, contact = new Contact(contactId, author, localAuthorId,
@@ -128,9 +119,9 @@ public class DatabaseComponentImplTest extends BriarTestCase {
final ShutdownManager shutdown = context.mock(ShutdownManager.class); final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final EventBus eventBus = context.mock(EventBus.class); final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
exactly(10).of(database).startTransaction(); exactly(9).of(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
exactly(10).of(database).commitTransaction(txn); exactly(9).of(database).commitTransaction(txn);
// open() // open()
oneOf(database).open(); oneOf(database).open();
will(returnValue(false)); will(returnValue(false));
@@ -150,9 +141,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
// getContacts() // getContacts()
oneOf(database).getContacts(txn); oneOf(database).getContacts(txn);
will(returnValue(Collections.singletonList(contact))); will(returnValue(Collections.singletonList(contact)));
// getRemoteProperties()
oneOf(database).getRemoteProperties(txn, transportId);
will(returnValue(Collections.emptyMap()));
// addGroup() // addGroup()
oneOf(database).containsGroup(txn, groupId); oneOf(database).containsGroup(txn, groupId);
will(returnValue(false)); will(returnValue(false));
@@ -194,8 +182,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
db.addLocalAuthor(localAuthor); db.addLocalAuthor(localAuthor);
assertEquals(contactId, db.addContact(author, localAuthorId)); assertEquals(contactId, db.addContact(author, localAuthorId));
assertEquals(Collections.singletonList(contact), db.getContacts()); assertEquals(Collections.singletonList(contact), db.getContacts());
assertEquals(Collections.emptyMap(),
db.getRemoteProperties(transportId));
db.addGroup(group); // First time - listeners called db.addGroup(group); // First time - listeners called
db.addGroup(group); // Second time - not called db.addGroup(group); // Second time - not called
assertEquals(Collections.singletonList(group), db.getGroups(clientId)); assertEquals(Collections.singletonList(group), db.getGroups(clientId));
@@ -310,11 +296,11 @@ public class DatabaseComponentImplTest extends BriarTestCase {
final EventBus eventBus = context.mock(EventBus.class); final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Check whether the contact is in the DB (which it's not) // Check whether the contact is in the DB (which it's not)
exactly(21).of(database).startTransaction(); exactly(17).of(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
exactly(21).of(database).containsContact(txn, contactId); exactly(17).of(database).containsContact(txn, contactId);
will(returnValue(false)); will(returnValue(false));
exactly(21).of(database).abortTransaction(txn); exactly(17).of(database).abortTransaction(txn);
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown); shutdown);
@@ -361,20 +347,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
// Expected // Expected
} }
try {
db.generateTransportAcks(contactId);
fail();
} catch (NoSuchContactException expected) {
// Expected
}
try {
db.generateTransportUpdates(contactId, 123);
fail();
} catch (NoSuchContactException expected) {
// Expected
}
try { try {
db.getContact(contactId); db.getContact(contactId);
fail(); fail();
@@ -443,23 +415,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
// Expected // Expected
} }
try {
TransportAck a = new TransportAck(transportId, 0);
db.receiveTransportAck(contactId, a);
fail();
} catch (NoSuchContactException expected) {
// Expected
}
try {
TransportUpdate u = new TransportUpdate(transportId,
transportProperties, 1);
db.receiveTransportUpdate(contactId, u);
fail();
} catch (NoSuchContactException expected) {
// Expected
}
try { try {
db.removeContact(contactId); db.removeContact(contactId);
fail(); fail();
@@ -677,13 +632,13 @@ public class DatabaseComponentImplTest extends BriarTestCase {
will(returnValue(contactId)); will(returnValue(contactId));
oneOf(database).commitTransaction(txn); oneOf(database).commitTransaction(txn);
// Check whether the transport is in the DB (which it's not) // Check whether the transport is in the DB (which it's not)
exactly(6).of(database).startTransaction(); exactly(4).of(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
exactly(2).of(database).containsContact(txn, contactId); exactly(2).of(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
exactly(6).of(database).containsTransport(txn, transportId); exactly(4).of(database).containsTransport(txn, transportId);
will(returnValue(false)); will(returnValue(false));
exactly(6).of(database).abortTransaction(txn); exactly(4).of(database).abortTransaction(txn);
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown); shutdown);
@@ -691,13 +646,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
db.addLocalAuthor(localAuthor); db.addLocalAuthor(localAuthor);
assertEquals(contactId, db.addContact(author, localAuthorId)); assertEquals(contactId, db.addContact(author, localAuthorId));
try {
db.getLocalProperties(transportId);
fail();
} catch (NoSuchTransportException expected) {
// Expected
}
try { try {
db.getTransportKeys(transportId); db.getTransportKeys(transportId);
fail(); fail();
@@ -705,13 +653,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
// Expected // Expected
} }
try {
db.mergeLocalProperties(transportId, new TransportProperties());
fail();
} catch (NoSuchTransportException expected) {
// Expected
}
try { try {
db.incrementStreamCounter(contactId, transportId, 0); db.incrementStreamCounter(contactId, transportId, 0);
fail(); fail();
@@ -952,62 +893,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
@Test
public void testGenerateTransportUpdatesNoUpdatesDue() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getTransportUpdates(txn, contactId, maxLatency);
will(returnValue(null));
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
assertNull(db.generateTransportUpdates(contactId, maxLatency));
context.assertIsSatisfied();
}
@Test
public void testGenerateTransportUpdates() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getTransportUpdates(txn, contactId, maxLatency);
will(returnValue(Collections.singletonList(new TransportUpdate(
transportId, transportProperties, 1))));
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
Collection<TransportUpdate> updates =
db.generateTransportUpdates(contactId, maxLatency);
assertNotNull(updates);
assertEquals(1, updates.size());
TransportUpdate u = updates.iterator().next();
assertEquals(transportId, u.getId());
assertEquals(transportProperties, u.getProperties());
assertEquals(1, u.getVersion());
context.assertIsSatisfied();
}
@Test @Test
public void testReceiveAck() throws Exception { public void testReceiveAck() throws Exception {
Mockery context = new Mockery(); Mockery context = new Mockery();
@@ -1253,116 +1138,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
@Test
public void testReceiveTransportAck() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).containsTransport(txn, transportId);
will(returnValue(true));
oneOf(database).setTransportUpdateAcked(txn, contactId,
transportId, 1);
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
TransportAck a = new TransportAck(transportId, 1);
db.receiveTransportAck(contactId, a);
context.assertIsSatisfied();
}
@Test
public void testReceiveTransportUpdate() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).setRemoteProperties(txn, contactId, transportId,
transportProperties, 1);
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
TransportUpdate u = new TransportUpdate(transportId,
transportProperties, 1);
db.receiveTransportUpdate(contactId, u);
context.assertIsSatisfied();
}
@Test
public void testChangingLocalTransportPropertiesCallsListeners()
throws Exception {
final TransportProperties properties =
new TransportProperties(Collections.singletonMap("bar", "baz"));
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsTransport(txn, transportId);
will(returnValue(true));
oneOf(database).getLocalProperties(txn, transportId);
will(returnValue(new TransportProperties()));
oneOf(database).mergeLocalProperties(txn, transportId, properties);
oneOf(database).commitTransaction(txn);
oneOf(eventBus).broadcast(with(any(
LocalTransportsUpdatedEvent.class)));
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
db.mergeLocalProperties(transportId, properties);
context.assertIsSatisfied();
}
@Test
public void testNotChangingLocalTransportPropertiesDoesNotCallListeners()
throws Exception {
final TransportProperties properties =
new TransportProperties(Collections.singletonMap("bar", "baz"));
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsTransport(txn, transportId);
will(returnValue(true));
oneOf(database).getLocalProperties(txn, transportId);
will(returnValue(properties));
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
db.mergeLocalProperties(transportId, properties);
context.assertIsSatisfied();
}
@Test @Test
public void testChangingVisibilityCallsListeners() throws Exception { public void testChangingVisibilityCallsListeners() throws Exception {
final ContactId contactId1 = new ContactId(123); final ContactId contactId1 = new ContactId(123);

View File

@@ -3,9 +3,7 @@ package org.briarproject.db;
import org.briarproject.BriarTestCase; import org.briarproject.BriarTestCase;
import org.briarproject.TestDatabaseConfig; import org.briarproject.TestDatabaseConfig;
import org.briarproject.TestUtils; import org.briarproject.TestUtils;
import org.briarproject.api.Settings;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
@@ -14,6 +12,7 @@ import org.briarproject.api.db.StorageStatus;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
@@ -29,6 +28,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.io.File; import java.io.File;
import java.security.SecureRandom;
import java.sql.Connection; import java.sql.Connection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -137,8 +137,6 @@ public class H2DatabaseTest extends BriarTestCase {
db = open(true); db = open(true);
txn = db.startTransaction(); txn = db.startTransaction();
assertFalse(db.containsContact(txn, contactId)); assertFalse(db.containsContact(txn, contactId));
assertEquals(Collections.emptyMap(),
db.getRemoteProperties(txn, transportId));
assertFalse(db.containsGroup(txn, groupId)); assertFalse(db.containsGroup(txn, groupId));
assertFalse(db.containsMessage(txn, messageId)); assertFalse(db.containsMessage(txn, messageId));
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -502,71 +500,6 @@ public class H2DatabaseTest extends BriarTestCase {
assertFalse(error.get()); assertFalse(error.get());
} }
@Test
public void testUpdateRemoteTransportProperties() throws Exception {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a contact with a transport
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
TransportProperties p = new TransportProperties(
Collections.singletonMap("foo", "bar"));
db.setRemoteProperties(txn, contactId, transportId, p, 1);
assertEquals(Collections.singletonMap(contactId, p),
db.getRemoteProperties(txn, transportId));
// Replace the transport properties
TransportProperties p1 = new TransportProperties(
Collections.singletonMap("baz", "bam"));
db.setRemoteProperties(txn, contactId, transportId, p1, 2);
assertEquals(Collections.singletonMap(contactId, p1),
db.getRemoteProperties(txn, transportId));
// Remove the transport properties
TransportProperties p2 = new TransportProperties();
db.setRemoteProperties(txn, contactId, transportId, p2, 3);
assertEquals(Collections.emptyMap(),
db.getRemoteProperties(txn, transportId));
db.commitTransaction(txn);
db.close();
}
@Test
public void testUpdateLocalTransportProperties() throws Exception {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a transport to the database
db.addTransport(txn, transportId, 123);
// Set the transport properties
TransportProperties p = new TransportProperties();
p.put("foo", "foo");
p.put("bar", "bar");
db.mergeLocalProperties(txn, transportId, p);
assertEquals(p, db.getLocalProperties(txn, transportId));
assertEquals(Collections.singletonMap(transportId, p),
db.getLocalProperties(txn));
// Update one of the properties and add another
TransportProperties p1 = new TransportProperties();
p1.put("bar", "baz");
p1.put("bam", "bam");
db.mergeLocalProperties(txn, transportId, p1);
TransportProperties merged = new TransportProperties();
merged.put("foo", "foo");
merged.put("bar", "baz");
merged.put("bam", "bam");
assertEquals(merged, db.getLocalProperties(txn, transportId));
assertEquals(Collections.singletonMap(transportId, merged),
db.getLocalProperties(txn));
db.commitTransaction(txn);
db.close();
}
@Test @Test
public void testUpdateSettings() throws Exception { public void testUpdateSettings() throws Exception {
Database<Connection> db = open(false); Database<Connection> db = open(false);
@@ -597,42 +530,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.close(); db.close();
} }
@Test
public void testTransportsNotUpdatedIfVersionIsOld() throws Exception {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a contact
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
// Initialise the transport properties with version 1
TransportProperties p = new TransportProperties(
Collections.singletonMap("foo", "bar"));
assertTrue(db.setRemoteProperties(txn, contactId, transportId, p, 1));
assertEquals(Collections.singletonMap(contactId, p),
db.getRemoteProperties(txn, transportId));
// Replace the transport properties with version 2
TransportProperties p1 = new TransportProperties(
Collections.singletonMap("baz", "bam"));
assertTrue(db.setRemoteProperties(txn, contactId, transportId, p1, 2));
assertEquals(Collections.singletonMap(contactId, p1),
db.getRemoteProperties(txn, transportId));
// Try to replace the transport properties with version 1
TransportProperties p2 = new TransportProperties(
Collections.singletonMap("quux", "etc"));
assertFalse(db.setRemoteProperties(txn, contactId, transportId, p2, 1));
// Version 2 of the properties should still be there
assertEquals(Collections.singletonMap(contactId, p1),
db.getRemoteProperties(txn, transportId));
db.commitTransaction(txn);
db.close();
}
@Test @Test
public void testContainsVisibleMessageRequiresMessageInDatabase() public void testContainsVisibleMessageRequiresMessageInDatabase()
throws Exception { throws Exception {
@@ -1225,7 +1122,7 @@ public class H2DatabaseTest extends BriarTestCase {
private Database<Connection> open(boolean resume) throws Exception { private Database<Connection> open(boolean resume) throws Exception {
Database<Connection> db = new H2Database(new TestDatabaseConfig(testDir, Database<Connection> db = new H2Database(new TestDatabaseConfig(testDir,
MAX_SIZE), new SystemClock()); MAX_SIZE), new SecureRandom(), new SystemClock());
if (!resume) TestUtils.deleteTestDirectory(testDir); if (!resume) TestUtils.deleteTestDirectory(testDir);
db.open(); db.open();
return db; return db;

View File

@@ -0,0 +1,14 @@
package org.briarproject.forum;
import org.briarproject.BriarTestCase;
import org.junit.Test;
import static org.junit.Assert.fail;
public class ForumManagerImplTest extends BriarTestCase {
@Test
public void testUnitTestsExist() {
fail(); // FIXME: Write tests
}
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.forum;
import org.briarproject.BriarTestCase;
import org.junit.Test;
import static org.junit.Assert.fail;
public class ForumPostValidatorTest extends BriarTestCase {
@Test
public void testUnitTestsExist() {
fail(); // FIXME: Write tests
}
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.messaging;
import org.briarproject.BriarTestCase;
import org.junit.Test;
import static org.junit.Assert.fail;
public class MessagingManagerImplTest extends BriarTestCase {
@Test
public void testUnitTestsExist() {
fail(); // FIXME: Write tests
}
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.messaging;
import org.briarproject.BriarTestCase;
import org.junit.Test;
import static org.junit.Assert.fail;
public class PrivateMessageValidatorTest extends BriarTestCase {
@Test
public void testUnitTestsExist() {
fail(); // FIXME: Write tests
}
}

View File

@@ -1,11 +1,11 @@
package org.briarproject.plugins; package org.briarproject.plugins;
import org.briarproject.api.Settings;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.settings.Settings;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;

View File

@@ -1,10 +1,10 @@
package org.briarproject.plugins; package org.briarproject.plugins;
import org.briarproject.api.Settings;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.settings.Settings;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;

View File

@@ -13,7 +13,7 @@ import org.briarproject.api.plugins.simplex.SimplexPlugin;
import org.briarproject.api.plugins.simplex.SimplexPluginCallback; import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
import org.briarproject.api.plugins.simplex.SimplexPluginConfig; import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
import org.briarproject.api.plugins.simplex.SimplexPluginFactory; import org.briarproject.api.plugins.simplex.SimplexPluginFactory;
import org.briarproject.api.property.TransportPropertyManager; import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.api.system.Clock; import org.briarproject.api.system.Clock;
import org.briarproject.api.ui.UiCallback; import org.briarproject.api.ui.UiCallback;
import org.briarproject.system.SystemClock; import org.briarproject.system.SystemClock;

View File

@@ -1,8 +1,8 @@
package org.briarproject.plugins.bluetooth; package org.briarproject.plugins.bluetooth;
import org.briarproject.api.Settings;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.settings.Settings;
import org.briarproject.plugins.DuplexClientTest; import org.briarproject.plugins.DuplexClientTest;
import org.briarproject.system.SystemClock; import org.briarproject.system.SystemClock;

View File

@@ -1,7 +1,7 @@
package org.briarproject.plugins.bluetooth; package org.briarproject.plugins.bluetooth;
import org.briarproject.api.Settings; import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.TransportProperties; import org.briarproject.api.settings.Settings;
import org.briarproject.plugins.DuplexServerTest; import org.briarproject.plugins.DuplexServerTest;
import org.briarproject.system.SystemClock; import org.briarproject.system.SystemClock;

View File

@@ -1,9 +1,9 @@
package org.briarproject.plugins.modem; package org.briarproject.plugins.modem;
import org.briarproject.BriarTestCase; import org.briarproject.BriarTestCase;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.properties.TransportProperties;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.jmock.Mockery; import org.jmock.Mockery;
import org.junit.Test; import org.junit.Test;

View File

@@ -1,8 +1,8 @@
package org.briarproject.plugins.tcp; package org.briarproject.plugins.tcp;
import org.briarproject.api.Settings;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.settings.Settings;
import org.briarproject.plugins.DuplexClientTest; import org.briarproject.plugins.DuplexClientTest;
import java.util.Collections; import java.util.Collections;

View File

@@ -1,12 +1,12 @@
package org.briarproject.plugins.tcp; package org.briarproject.plugins.tcp;
import org.briarproject.BriarTestCase; import org.briarproject.BriarTestCase;
import org.briarproject.api.Settings;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.settings.Settings;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;

View File

@@ -1,7 +1,7 @@
package org.briarproject.plugins.tcp; package org.briarproject.plugins.tcp;
import org.briarproject.api.Settings; import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.TransportProperties; import org.briarproject.api.settings.Settings;
import org.briarproject.plugins.DuplexServerTest; import org.briarproject.plugins.DuplexServerTest;
import java.util.Collections; import java.util.Collections;

View File

@@ -0,0 +1,14 @@
package org.briarproject.properties;
import org.briarproject.BriarTestCase;
import org.junit.Test;
import static org.junit.Assert.fail;
public class TransportPropertyManagerImplTest extends BriarTestCase {
@Test
public void testUnitTestsExist() {
fail(); // FIXME: Write tests
}
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.properties;
import org.briarproject.BriarTestCase;
import org.junit.Test;
import static org.junit.Assert.fail;
public class TransportPropertyValidatorTest extends BriarTestCase {
@Test
public void testUnitTestsExist() {
fail(); // FIXME: Write tests
}
}

View File

@@ -8,8 +8,6 @@ import org.briarproject.TestDatabaseModule;
import org.briarproject.TestLifecycleModule; import org.briarproject.TestLifecycleModule;
import org.briarproject.TestSystemModule; import org.briarproject.TestSystemModule;
import org.briarproject.TestUtils; import org.briarproject.TestUtils;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.UniqueId; import org.briarproject.api.UniqueId;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyPair; import org.briarproject.api.crypto.KeyPair;
@@ -34,7 +32,6 @@ import org.briarproject.api.sync.PacketWriter;
import org.briarproject.api.sync.PacketWriterFactory; import org.briarproject.api.sync.PacketWriterFactory;
import org.briarproject.api.sync.Request; import org.briarproject.api.sync.Request;
import org.briarproject.api.sync.SubscriptionUpdate; import org.briarproject.api.sync.SubscriptionUpdate;
import org.briarproject.api.sync.TransportUpdate;
import org.briarproject.contact.ContactModule; import org.briarproject.contact.ContactModule;
import org.briarproject.crypto.CryptoModule; import org.briarproject.crypto.CryptoModule;
import org.briarproject.data.DataModule; import org.briarproject.data.DataModule;
@@ -50,9 +47,6 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Random; import java.util.Random;
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.api.TransportPropertyConstants.MAX_TRANSPORT_ID_LENGTH;
import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH; import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
@@ -194,27 +188,6 @@ public class ConstantsTest extends BriarTestCase {
testMessageIdsFitIntoRequest(1000); testMessageIdsFitIntoRequest(1000);
} }
@Test
public void testPropertiesFitIntoTransportUpdate() throws Exception {
// Create the maximum number of properties with the maximum length
TransportProperties p = new TransportProperties();
for (int i = 0; i < MAX_PROPERTIES_PER_TRANSPORT; i++) {
String key = TestUtils.createRandomString(MAX_PROPERTY_LENGTH);
String value = TestUtils.createRandomString(MAX_PROPERTY_LENGTH);
p.put(key, value);
}
// Create a maximum-length transport update
String idString = TestUtils.createRandomString(MAX_TRANSPORT_ID_LENGTH);
TransportId id = new TransportId(idString);
TransportUpdate u = new TransportUpdate(id, p, Long.MAX_VALUE);
// Serialise the update
ByteArrayOutputStream out = new ByteArrayOutputStream();
PacketWriter writer = packetWriterFactory.createPacketWriter(out);
writer.writeTransportUpdate(u);
// Check the size of the serialised transport update
assertTrue(out.size() <= MAX_PACKET_PAYLOAD_LENGTH);
}
@Test @Test
public void testGroupsFitIntoSubscriptionUpdate() throws Exception { public void testGroupsFitIntoSubscriptionUpdate() throws Exception {
// Create the maximum number of maximum-length groups // Create the maximum number of maximum-length groups

View File

@@ -54,7 +54,6 @@ import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Collections;
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
@@ -132,8 +131,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
new byte[MAX_PUBLIC_KEY_LENGTH]); new byte[MAX_PUBLIC_KEY_LENGTH]);
ContactId contactId = contactManager.addContact(bobAuthor, aliceId); ContactId contactId = contactManager.addContact(bobAuthor, aliceId);
// Derive and store the transport keys // Derive and store the transport keys
keyManager.addContact(contactId, Collections.singletonList(transportId), keyManager.addContact(contactId, master, timestamp, true);
master, timestamp, true);
// Send Bob a message // Send Bob a message
GroupId groupId = messagingManager.getConversationId(contactId); GroupId groupId = messagingManager.getConversationId(contactId);
@@ -198,8 +196,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
new byte[MAX_PUBLIC_KEY_LENGTH]); new byte[MAX_PUBLIC_KEY_LENGTH]);
ContactId contactId = contactManager.addContact(aliceAuthor, bobId); ContactId contactId = contactManager.addContact(aliceAuthor, bobId);
// Derive and store the transport keys // Derive and store the transport keys
keyManager.addContact(contactId, Collections.singletonList(transportId), keyManager.addContact(contactId, master, timestamp, false);
master, timestamp, false);
// Set up an event listener // Set up an event listener
MessageListener listener = new MessageListener(); MessageListener listener = new MessageListener();

View File

@@ -52,12 +52,6 @@ public class SimplexOutgoingSessionTest extends BriarTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Add listener // Add listener
oneOf(eventBus).addListener(session); oneOf(eventBus).addListener(session);
// No transport acks to send
oneOf(db).generateTransportAcks(contactId);
will(returnValue(null));
// No transport updates to send
oneOf(db).generateTransportUpdates(contactId, maxLatency);
will(returnValue(null));
// No subscription ack to send // No subscription ack to send
oneOf(db).generateSubscriptionAck(contactId); oneOf(db).generateSubscriptionAck(contactId);
will(returnValue(null)); will(returnValue(null));
@@ -92,12 +86,6 @@ public class SimplexOutgoingSessionTest extends BriarTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Add listener // Add listener
oneOf(eventBus).addListener(session); oneOf(eventBus).addListener(session);
// No transport acks to send
oneOf(db).generateTransportAcks(contactId);
will(returnValue(null));
// No transport updates to send
oneOf(db).generateTransportUpdates(contactId, maxLatency);
will(returnValue(null));
// No subscription ack to send // No subscription ack to send
oneOf(db).generateSubscriptionAck(contactId); oneOf(db).generateSubscriptionAck(contactId);
will(returnValue(null)); will(returnValue(null));