mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
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:
@@ -13,7 +13,7 @@
|
||||
<item>org.briarproject.lifecycle.LifecycleModule</item>
|
||||
<item>org.briarproject.messaging.MessagingModule</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.system.AndroidSystemModule</item>
|
||||
<item>org.briarproject.transport.TransportModule</item>
|
||||
|
||||
@@ -11,7 +11,6 @@ import android.support.v4.app.TaskStackBuilder;
|
||||
import org.briarproject.R;
|
||||
import org.briarproject.android.contact.ConversationActivity;
|
||||
import org.briarproject.android.forum.ForumActivity;
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.android.AndroidExecutor;
|
||||
import org.briarproject.api.android.AndroidNotificationManager;
|
||||
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.lifecycle.Service;
|
||||
import org.briarproject.api.messaging.MessagingManager;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
@@ -29,13 +29,13 @@ import org.briarproject.android.util.HorizontalBorder;
|
||||
import org.briarproject.android.util.LayoutUtils;
|
||||
import org.briarproject.android.util.ListLoadingProgressBar;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.android.AndroidExecutor;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
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 java.io.File;
|
||||
|
||||
@@ -25,12 +25,12 @@ import org.briarproject.android.util.FixedVerticalSpace;
|
||||
import org.briarproject.android.util.HorizontalBorder;
|
||||
import org.briarproject.android.util.LayoutUtils;
|
||||
import org.briarproject.android.util.ListLoadingProgressBar;
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.SettingsUpdatedEvent;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.api.settings.SettingsManager;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package org.briarproject.android.invitation;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.R;
|
||||
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.crypto.CryptoComponent;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
@@ -60,8 +56,6 @@ implements InvitationListener {
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject private volatile IdentityManager identityManager;
|
||||
private volatile boolean bluetoothWasEnabled = false;
|
||||
private volatile boolean leaveBluetoothEnabled = false;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
@@ -69,9 +63,6 @@ implements InvitationListener {
|
||||
if (state == null) {
|
||||
// This is a new activity
|
||||
setView(new ChooseIdentityView(this));
|
||||
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (adapter != null) bluetoothWasEnabled = adapter.isEnabled();
|
||||
} else {
|
||||
// Restore the activity's state
|
||||
byte[] b = state.getByteArray("briar.LOCAL_AUTHOR_ID");
|
||||
@@ -79,8 +70,6 @@ implements InvitationListener {
|
||||
taskHandle = state.getLong("briar.TASK_HANDLE", -1);
|
||||
task = referenceManager.getReference(taskHandle,
|
||||
InvitationTask.class);
|
||||
bluetoothWasEnabled =
|
||||
state.getBoolean("briar.BLUETOOTH_WAS_ENABLED");
|
||||
|
||||
if (task == null) {
|
||||
// No background task - we must be in an initial or final state
|
||||
@@ -162,26 +151,6 @@ implements InvitationListener {
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
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
|
||||
@@ -196,15 +165,12 @@ implements InvitationListener {
|
||||
state.putBoolean("briar.FAILED", connectionFailed);
|
||||
state.putString("briar.CONTACT_NAME", contactName);
|
||||
if (task != null) state.putLong("briar.TASK_HANDLE", taskHandle);
|
||||
state.putBoolean("briar.BLUETOOTH_WAS_ENABLED", bluetoothWasEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if (task != null) task.removeListener(this);
|
||||
if (isFinishing()) disableBluetooth();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -295,7 +261,7 @@ implements InvitationListener {
|
||||
setView(new InvitationCodeView(this, true));
|
||||
|
||||
task = invitationTaskFactory.createTask(localAuthorId,
|
||||
localInvitationCode, code, leaveBluetoothEnabled);
|
||||
localInvitationCode, code);
|
||||
taskHandle = referenceManager.putReference(task, InvitationTask.class);
|
||||
task.addListener(AddContactActivity.this);
|
||||
// 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() {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
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.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
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 {
|
||||
|
||||
private final int error;
|
||||
@@ -39,8 +35,6 @@ class ErrorView extends AddContactView implements OnClickListener {
|
||||
removeAllViews();
|
||||
Context ctx = getContext();
|
||||
|
||||
container.disableBluetooth();
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) ctx.getSystemService
|
||||
(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View view = inflater.inflate(R.layout.invitation_error, this);
|
||||
|
||||
@@ -10,13 +10,13 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.android.AndroidExecutor;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.util.LatchedReference;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
@@ -13,9 +13,7 @@ import net.freehaven.tor.control.TorControlConnection;
|
||||
import net.sourceforge.jsocks.socks.Socks5Proxy;
|
||||
import net.sourceforge.jsocks.socks.SocksSocket;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
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.DuplexPluginCallback;
|
||||
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.util.StringUtils;
|
||||
|
||||
|
||||
16
briar-api/src/org/briarproject/api/DeviceId.java
Normal file
16
briar-api/src/org/briarproject/api/DeviceId.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package org.briarproject.api;
|
||||
import java.util.Hashtable;
|
||||
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;
|
||||
|
||||
@@ -26,4 +26,18 @@ abstract class StringMap extends Hashtable<String, String> {
|
||||
public void putBoolean(String key, boolean 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
|
||||
public TransportId(String id) {
|
||||
@@ -21,8 +22,7 @@ public class TransportId {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof TransportId) return id.equals(((TransportId) o).id);
|
||||
return false;
|
||||
return o instanceof TransportId && id.equals(((TransportId) o).id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package org.briarproject.api.db;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.DeviceId;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.identity.AuthorId;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.api.sync.Ack;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
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.SubscriptionAck;
|
||||
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 java.io.IOException;
|
||||
@@ -34,7 +32,7 @@ import java.util.Map;
|
||||
public interface DatabaseComponent {
|
||||
|
||||
/** 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. */
|
||||
void close() throws DbException, IOException;
|
||||
@@ -125,21 +123,6 @@ public interface DatabaseComponent {
|
||||
SubscriptionUpdate generateSubscriptionUpdate(ContactId c, int maxLatency)
|
||||
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
|
||||
* subscribe.
|
||||
@@ -155,6 +138,9 @@ public interface DatabaseComponent {
|
||||
/** Returns all contacts associated with the given local pseudonym. */
|
||||
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. */
|
||||
Group getGroup(GroupId g) throws DbException;
|
||||
|
||||
@@ -173,13 +159,6 @@ public interface DatabaseComponent {
|
||||
/** Returns all local pseudonyms. */
|
||||
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
|
||||
* client.
|
||||
@@ -210,10 +189,6 @@ public interface DatabaseComponent {
|
||||
MessageStatus getMessageStatus(ContactId c, MessageId m)
|
||||
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. */
|
||||
Settings getSettings(String namespace) throws DbException;
|
||||
|
||||
@@ -243,13 +218,6 @@ public interface DatabaseComponent {
|
||||
*/
|
||||
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
|
||||
* message.
|
||||
@@ -282,13 +250,6 @@ public interface DatabaseComponent {
|
||||
void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate u)
|
||||
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. */
|
||||
void removeContact(ContactId c) throws DbException;
|
||||
|
||||
@@ -320,13 +281,6 @@ public interface DatabaseComponent {
|
||||
void setMessageValidity(Message m, ClientId c, boolean valid)
|
||||
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
|
||||
* given rotation period.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -7,5 +7,5 @@ public interface InvitationTaskFactory {
|
||||
|
||||
/** Creates a task using the given pseudonym and invitation codes. */
|
||||
InvitationTask createTask(AuthorId localAuthorId, int localCode,
|
||||
int remoteCode, boolean reuseConnection);
|
||||
int remoteCode);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.briarproject.api.plugins;
|
||||
|
||||
import org.briarproject.api.TransportProperties;
|
||||
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;
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
package org.briarproject.api;
|
||||
package org.briarproject.api.properties;
|
||||
|
||||
import org.briarproject.api.StringMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
package org.briarproject.api;
|
||||
package org.briarproject.api.properties;
|
||||
|
||||
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. */
|
||||
int MAX_PROPERTIES_PER_TRANSPORT = 100;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.briarproject.api.property;
|
||||
package org.briarproject.api.properties;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
|
||||
@@ -26,11 +25,4 @@ public interface TransportPropertyManager {
|
||||
*/
|
||||
void mergeLocalProperties(TransportId t, TransportProperties p)
|
||||
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;
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
package org.briarproject.api;
|
||||
package org.briarproject.api.settings;
|
||||
|
||||
import org.briarproject.api.StringMap;
|
||||
|
||||
public class Settings extends StringMap {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.briarproject.api.settings;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.db.DbException;
|
||||
|
||||
public interface SettingsManager {
|
||||
|
||||
@@ -23,10 +23,4 @@ public interface PacketReader {
|
||||
|
||||
boolean hasSubscriptionUpdate() throws IOException;
|
||||
SubscriptionUpdate readSubscriptionUpdate() throws IOException;
|
||||
|
||||
boolean hasTransportAck() throws IOException;
|
||||
TransportAck readTransportAck() throws IOException;
|
||||
|
||||
boolean hasTransportUpdate() throws IOException;
|
||||
TransportUpdate readTransportUpdate() throws IOException;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,4 @@ public interface PacketTypes {
|
||||
byte REQUEST = 3;
|
||||
byte SUBSCRIPTION_ACK = 6;
|
||||
byte SUBSCRIPTION_UPDATE = 7;
|
||||
byte TRANSPORT_ACK = 8;
|
||||
byte TRANSPORT_UPDATE = 9;
|
||||
}
|
||||
|
||||
@@ -22,9 +22,5 @@ public interface PacketWriter {
|
||||
|
||||
void writeSubscriptionUpdate(SubscriptionUpdate u) throws IOException;
|
||||
|
||||
void writeTransportAck(TransportAck a) throws IOException;
|
||||
|
||||
void writeTransportUpdate(TransportUpdate u) throws IOException;
|
||||
|
||||
void flush() throws IOException;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Responsible for managing transport keys and recognising the pseudo-random
|
||||
* tags of incoming streams.
|
||||
@@ -18,8 +16,8 @@ public interface KeyManager {
|
||||
* {@link StreamContext StreamContexts} for the contact can be created
|
||||
* after this method has returned.
|
||||
*/
|
||||
void addContact(ContactId c, Collection<TransportId> transports,
|
||||
SecretKey master, long timestamp, boolean alice);
|
||||
void addContact(ContactId c, SecretKey master, long timestamp,
|
||||
boolean alice);
|
||||
|
||||
/**
|
||||
* Returns a {@link StreamContext} for sending a stream to the given
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.briarproject.api.crypto.StreamDecrypterFactory;
|
||||
import org.briarproject.api.crypto.StreamEncrypterFactory;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -57,4 +58,9 @@ public class CryptoModule extends AbstractModule {
|
||||
lifecycleManager.registerForShutdown(cryptoExecutor);
|
||||
return cryptoExecutor;
|
||||
}
|
||||
|
||||
@Provides
|
||||
SecureRandom getSecureRandom(CryptoComponent crypto) {
|
||||
return crypto.getSecureRandom();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package org.briarproject.db;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.DeviceId;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
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.AuthorId;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.Group;
|
||||
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.SubscriptionAck;
|
||||
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 java.io.IOException;
|
||||
@@ -43,7 +41,7 @@ interface Database<T> {
|
||||
* <p>
|
||||
* Locking: write.
|
||||
*/
|
||||
boolean open() throws DbException, IOException;
|
||||
boolean open() throws DbException;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
@@ -403,14 +392,6 @@ interface Database<T> {
|
||||
*/
|
||||
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
|
||||
* 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,
|
||||
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.
|
||||
* <p>
|
||||
@@ -476,16 +448,6 @@ interface Database<T> {
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
@@ -529,15 +491,6 @@ interface Database<T> {
|
||||
void mergeGroupMetadata(T txn, GroupId g, Metadata meta)
|
||||
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
|
||||
* message.
|
||||
@@ -689,26 +642,6 @@ interface Database<T> {
|
||||
boolean setGroups(T txn, ContactId c, Collection<Group> groups,
|
||||
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,
|
||||
* 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)
|
||||
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.
|
||||
* <p>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package org.briarproject.db;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.DeviceId;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
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.event.EventBus;
|
||||
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
|
||||
import org.briarproject.api.event.LocalTransportsUpdatedEvent;
|
||||
import org.briarproject.api.event.MessageAddedEvent;
|
||||
import org.briarproject.api.event.MessageRequestedEvent;
|
||||
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.MessagesSentEvent;
|
||||
import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent;
|
||||
import org.briarproject.api.event.RemoteTransportsUpdatedEvent;
|
||||
import org.briarproject.api.event.SettingsUpdatedEvent;
|
||||
import org.briarproject.api.event.SubscriptionAddedEvent;
|
||||
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.LocalAuthor;
|
||||
import org.briarproject.api.lifecycle.ShutdownManager;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.api.sync.Ack;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
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.SubscriptionAck;
|
||||
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 java.io.IOException;
|
||||
@@ -99,7 +95,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
this.shutdown = shutdown;
|
||||
}
|
||||
|
||||
public boolean open() throws DbException, IOException {
|
||||
public boolean open() throws DbException {
|
||||
Runnable shutdownHook = new Runnable() {
|
||||
public void run() {
|
||||
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 {
|
||||
lock.readLock().lock();
|
||||
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 {
|
||||
lock.readLock().lock();
|
||||
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)
|
||||
throws DbException {
|
||||
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 {
|
||||
lock.readLock().lock();
|
||||
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)
|
||||
throws DbException {
|
||||
lock.writeLock().lock();
|
||||
@@ -1208,52 +1098,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
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 {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
@@ -1390,25 +1234,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
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,
|
||||
long rotationPeriod, long base, byte[] bitmap) throws DbException {
|
||||
lock.writeLock().lock();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.briarproject.db;
|
||||
|
||||
import org.briarproject.api.settings.Settings;
|
||||
|
||||
interface DatabaseConstants {
|
||||
|
||||
/**
|
||||
@@ -8,4 +10,34 @@ interface DatabaseConstants {
|
||||
* limit is reached, additional offers will not be stored.
|
||||
*/
|
||||
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";
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@ import org.briarproject.api.db.DatabaseExecutor;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
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.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -39,13 +40,12 @@ public class DatabaseModule extends AbstractModule {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
// Nothing to bind
|
||||
}
|
||||
protected void configure() {}
|
||||
|
||||
@Provides @Singleton
|
||||
Database<Connection> getDatabase(DatabaseConfig config) {
|
||||
return new H2Database(config, new SystemClock());
|
||||
Database<Connection> getDatabase(DatabaseConfig config,
|
||||
SecureRandom random, Clock clock) {
|
||||
return new H2Database(config, random, clock);
|
||||
}
|
||||
|
||||
@Provides @Singleton
|
||||
|
||||
@@ -6,11 +6,10 @@ import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -18,7 +17,7 @@ import javax.inject.Inject;
|
||||
/** Contains all the H2-specific code for the database. */
|
||||
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 COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
|
||||
private static final String SECRET_TYPE = "BINARY(32)";
|
||||
@@ -27,16 +26,16 @@ class H2Database extends JdbcDatabase {
|
||||
private final String url;
|
||||
|
||||
@Inject
|
||||
H2Database(DatabaseConfig config, Clock clock) {
|
||||
super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, clock);
|
||||
H2Database(DatabaseConfig config, SecureRandom random, Clock clock) {
|
||||
super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, random, clock);
|
||||
this.config = config;
|
||||
String path = new File(config.getDatabaseDirectory(), "db").getAbsolutePath();
|
||||
// FIXME: Remove WRITE_DELAY=0 after implementing BTPv2?
|
||||
File dir = config.getDatabaseDirectory();
|
||||
String path = new File(dir, "db").getAbsolutePath();
|
||||
url = "jdbc:h2:split:" + path + ";CIPHER=AES;MULTI_THREADED=1"
|
||||
+ ";WRITE_DELAY=0;DB_CLOSE_ON_EXIT=false";
|
||||
}
|
||||
|
||||
public boolean open() throws DbException, IOException {
|
||||
public boolean open() throws DbException {
|
||||
boolean reopen = config.databaseExists();
|
||||
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
||||
super.open("org.h2.Driver", reopen);
|
||||
@@ -83,10 +82,4 @@ class H2Database extends JdbcDatabase {
|
||||
props.put("password", StringUtils.toHexString(key) + " password");
|
||||
return DriverManager.getConnection(url, props);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void flushBuffersToDisk(Statement s) throws SQLException {
|
||||
// FIXME: Remove this after implementing BTPv2?
|
||||
s.execute("CHECKPOINT SYNC");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.briarproject.db;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.DeviceId;
|
||||
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.ContactId;
|
||||
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.AuthorId;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.Group;
|
||||
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.SubscriptionAck;
|
||||
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.transport.IncomingKeys;
|
||||
import org.briarproject.api.transport.OutgoingKeys;
|
||||
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.PreparedStatement;
|
||||
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.UNKNOWN;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -65,8 +70,8 @@ import static org.briarproject.db.ExponentialBackoff.calculateExpiry;
|
||||
*/
|
||||
abstract class JdbcDatabase implements Database<Connection> {
|
||||
|
||||
private static final int SCHEMA_VERSION = 17;
|
||||
private static final int MIN_SCHEMA_VERSION = 17;
|
||||
private static final int SCHEMA_VERSION = 18;
|
||||
private static final int MIN_SCHEMA_VERSION = 18;
|
||||
|
||||
private static final String CREATE_SETTINGS =
|
||||
"CREATE TABLE settings"
|
||||
@@ -210,64 +215,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
+ " maxLatency INT NOT NULL,"
|
||||
+ " 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 =
|
||||
"CREATE TABLE incomingKeys"
|
||||
+ " (contactId INT NOT NULL,"
|
||||
@@ -306,6 +253,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
|
||||
// Different database libraries use different names for certain types
|
||||
private final String hashType, binaryType, counterType, secretType;
|
||||
private final SecureRandom random;
|
||||
private final Clock clock;
|
||||
|
||||
private final LinkedList<Connection> connections =
|
||||
@@ -318,22 +266,20 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
|
||||
protected abstract Connection createConnection() throws SQLException;
|
||||
|
||||
protected abstract void flushBuffersToDisk(Statement s) throws SQLException;
|
||||
|
||||
private final Lock connectionsLock = new ReentrantLock();
|
||||
private final Condition connectionsChanged = connectionsLock.newCondition();
|
||||
|
||||
JdbcDatabase(String hashType, String binaryType, String counterType,
|
||||
String secretType, Clock clock) {
|
||||
String secretType, SecureRandom random, Clock clock) {
|
||||
this.hashType = hashType;
|
||||
this.binaryType = binaryType;
|
||||
this.counterType = counterType;
|
||||
this.secretType = secretType;
|
||||
this.random = random;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
protected void open(String driverClass, boolean reopen) throws DbException,
|
||||
IOException {
|
||||
protected void open(String driverClass, boolean reopen) throws DbException {
|
||||
// Load the JDBC driver
|
||||
try {
|
||||
Class.forName(driverClass);
|
||||
@@ -347,10 +293,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
if (!checkSchemaVersion(txn)) throw new DbException();
|
||||
} else {
|
||||
createTables(txn);
|
||||
Settings s = new Settings();
|
||||
s.put("schemaVersion", String.valueOf(SCHEMA_VERSION));
|
||||
s.put("minSchemaVersion", String.valueOf(MIN_SCHEMA_VERSION));
|
||||
mergeSettings(txn, s, "db");
|
||||
storeSchemaVersion(txn);
|
||||
storeDeviceId(txn);
|
||||
}
|
||||
commitTransaction(txn);
|
||||
} catch (DbException e) {
|
||||
@@ -360,16 +304,27 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
private boolean checkSchemaVersion(Connection txn) throws DbException {
|
||||
try {
|
||||
Settings s = getSettings(txn, "db");
|
||||
int schemaVersion = Integer.valueOf(s.get("schemaVersion"));
|
||||
if (schemaVersion == SCHEMA_VERSION) return true;
|
||||
if (schemaVersion < MIN_SCHEMA_VERSION) return false;
|
||||
int minSchemaVersion = Integer.valueOf(s.get("minSchemaVersion"));
|
||||
return SCHEMA_VERSION >= minSchemaVersion;
|
||||
} catch (NumberFormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
Settings s = getSettings(txn, DB_SETTINGS_NAMESPACE);
|
||||
int schemaVersion = s.getInt(SCHEMA_VERSION_KEY, -1);
|
||||
if (schemaVersion == SCHEMA_VERSION) return true;
|
||||
if (schemaVersion < MIN_SCHEMA_VERSION) return false;
|
||||
int minSchemaVersion = s.getInt(MIN_SCHEMA_VERSION_KEY, -1);
|
||||
return SCHEMA_VERSION >= minSchemaVersion;
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -405,11 +360,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
s.executeUpdate(insertTypeNames(CREATE_OFFERS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_STATUSES));
|
||||
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_OUTGOING_KEYS));
|
||||
s.close();
|
||||
@@ -487,14 +437,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
public void commitTransaction(Connection txn) throws DbException {
|
||||
Statement s = null;
|
||||
try {
|
||||
txn.commit();
|
||||
s = txn.createStatement();
|
||||
flushBuffersToDisk(s);
|
||||
s.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(s);
|
||||
throw new DbException(e);
|
||||
}
|
||||
connectionsLock.lock();
|
||||
@@ -540,6 +485,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
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)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -589,9 +539,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != ids.size())
|
||||
throw new DbStateException();
|
||||
for (int i = 0; i < batchAffected.length; i++) {
|
||||
if (batchAffected[i] != 1) throw new DbStateException();
|
||||
}
|
||||
for (int rows : batchAffected)
|
||||
if (rows != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
}
|
||||
// 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();
|
||||
if (batchAffected.length != ids.size())
|
||||
throw new DbStateException();
|
||||
for (int i = 0; i < batchAffected.length; i++) {
|
||||
if (batchAffected[i] != 1) throw new DbStateException();
|
||||
}
|
||||
for (int rows : batchAffected)
|
||||
if (rows != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
}
|
||||
// Create a group version row
|
||||
@@ -629,31 +577,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
affected = ps.executeUpdate();
|
||||
if (affected != 1) throw new DbStateException();
|
||||
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;
|
||||
} catch (SQLException e) {
|
||||
tryToClose(rs);
|
||||
@@ -851,30 +774,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int affected = ps.executeUpdate();
|
||||
if (affected != 1) throw new DbStateException();
|
||||
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;
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps);
|
||||
@@ -920,9 +819,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ps.addBatch();
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != 3) throw new DbStateException();
|
||||
for (int i = 0; i < batchAffected.length; i++) {
|
||||
if (batchAffected[i] != 1) throw new DbStateException();
|
||||
}
|
||||
for (int rows : batchAffected)
|
||||
if (rows != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
// Store the outgoing keys
|
||||
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,
|
||||
GroupId g) throws DbException {
|
||||
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,
|
||||
ContactId c, int maxLength) throws DbException {
|
||||
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,
|
||||
TransportId t) throws DbException {
|
||||
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)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -2245,9 +1943,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != acked.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();
|
||||
for (int rows : batchAffected) {
|
||||
if (rows < 0) throw new DbStateException();
|
||||
if (rows > 1) throw new DbStateException();
|
||||
}
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
@@ -2271,76 +1969,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != requested.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();
|
||||
}
|
||||
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();
|
||||
for (int rows: batchAffected) {
|
||||
if (rows < 0) throw new DbStateException();
|
||||
if (rows > 1) throw new DbStateException();
|
||||
}
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
@@ -2383,9 +2014,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != removed.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();
|
||||
for (int rows : batchAffected) {
|
||||
if (rows < 0) throw new DbStateException();
|
||||
if (rows > 1) throw new DbStateException();
|
||||
}
|
||||
ps.close();
|
||||
}
|
||||
@@ -2403,9 +2034,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != retained.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();
|
||||
for (int rows : batchAffected) {
|
||||
if (rows < 0) throw new DbStateException();
|
||||
if (rows > 1) throw new DbStateException();
|
||||
}
|
||||
// Insert any keys that don't already exist
|
||||
sql = "INSERT INTO " + tableName
|
||||
@@ -2425,9 +2056,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
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();
|
||||
}
|
||||
for (int rows : batchAffected)
|
||||
if (rows != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps);
|
||||
@@ -2451,9 +2081,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != s.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();
|
||||
for (int rows : batchAffected) {
|
||||
if (rows < 0) throw new DbStateException();
|
||||
if (rows > 1) throw new DbStateException();
|
||||
}
|
||||
// Insert any settings that don't already exist
|
||||
sql = "INSERT INTO settings (key, value, namespace)"
|
||||
@@ -2472,9 +2102,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
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();
|
||||
}
|
||||
for (int rows : batchAffected)
|
||||
if (rows != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps);
|
||||
@@ -2586,9 +2215,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != visible.size())
|
||||
throw new DbStateException();
|
||||
for (int i = 0; i < batchAffected.length; i++) {
|
||||
if (batchAffected[i] != 1) throw new DbStateException();
|
||||
}
|
||||
for (int rows : batchAffected)
|
||||
if (rows != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps);
|
||||
@@ -2662,9 +2290,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != requested.size())
|
||||
throw new DbStateException();
|
||||
for (int i = 0; i < batchAffected.length; i++) {
|
||||
if (batchAffected[i] != 1) throw new DbStateException();
|
||||
}
|
||||
for (int rows : batchAffected)
|
||||
if (rows != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps);
|
||||
@@ -2734,7 +2361,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
public void setContactStatus(Connection txn, ContactId c, StorageStatus s)
|
||||
throws DbException {
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
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)
|
||||
throws DbException {
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "UPDATE messages SET valid = ? WHERE messageId = ?";
|
||||
@@ -2856,9 +2483,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != removed.size())
|
||||
throw new DbStateException();
|
||||
for (int i = 0; i < batchAffected.length; i++) {
|
||||
if (batchAffected[i] < 0) throw new DbStateException();
|
||||
}
|
||||
for (int rows : batchAffected)
|
||||
if (rows < 0) throw new DbStateException();
|
||||
ps.close();
|
||||
}
|
||||
// Delete the existing subscriptions, if any
|
||||
@@ -2882,130 +2508,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
if (batchAffected.length != groups.size())
|
||||
throw new DbStateException();
|
||||
for (int i = 0; i < batchAffected.length; i++) {
|
||||
if (batchAffected[i] != 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();
|
||||
}
|
||||
for (int rows : batchAffected)
|
||||
if (rows != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
return true;
|
||||
} 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)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
|
||||
@@ -16,6 +16,8 @@ import org.briarproject.api.system.Clock;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import static org.briarproject.forum.ForumManagerImpl.CLIENT_ID;
|
||||
|
||||
public class ForumModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
@@ -26,16 +28,14 @@ public class ForumModule extends AbstractModule {
|
||||
|
||||
@Provides @Singleton
|
||||
ForumPostValidator getValidator(ValidationManager validationManager,
|
||||
ForumManager forumManager, CryptoComponent crypto,
|
||||
BdfReaderFactory bdfReaderFactory,
|
||||
CryptoComponent crypto, BdfReaderFactory bdfReaderFactory,
|
||||
BdfWriterFactory bdfWriterFactory,
|
||||
ObjectReader<Author> authorReader, MetadataEncoder metadataEncoder,
|
||||
Clock clock) {
|
||||
ForumPostValidator validator = new ForumPostValidator(crypto,
|
||||
bdfReaderFactory, bdfWriterFactory, authorReader,
|
||||
metadataEncoder, clock);
|
||||
validationManager.registerMessageValidator(forumManager.getClientId(),
|
||||
validator);
|
||||
validationManager.registerMessageValidator(CLIENT_ID, validator);
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.briarproject.invitation;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
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.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.property.TransportPropertyManager;
|
||||
import org.briarproject.api.sync.GroupFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.KeyManager;
|
||||
@@ -28,7 +25,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
@@ -47,17 +43,12 @@ class AliceConnector extends Connector {
|
||||
StreamWriterFactory streamWriterFactory,
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionManager connectionManager,
|
||||
ContactManager contactManager,
|
||||
TransportPropertyManager transportPropertyManager, Clock clock,
|
||||
boolean reuseConnection, ConnectorGroup group, DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps,
|
||||
PseudoRandom random) {
|
||||
ContactManager contactManager, Clock clock, ConnectorGroup group,
|
||||
DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
|
||||
super(crypto, bdfReaderFactory, bdfWriterFactory, streamReaderFactory,
|
||||
streamWriterFactory, authorFactory, groupFactory,
|
||||
keyManager, connectionManager, contactManager,
|
||||
transportPropertyManager, clock, reuseConnection, group,
|
||||
plugin, localAuthor, localProps, random);
|
||||
streamWriterFactory, authorFactory, groupFactory, keyManager,
|
||||
connectionManager, contactManager, clock, group, plugin,
|
||||
localAuthor, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,20 +143,14 @@ class AliceConnector extends Connector {
|
||||
// Derive the invitation nonces
|
||||
byte[] aliceNonce = crypto.deriveSignatureNonce(master, true);
|
||||
byte[] bobNonce = crypto.deriveSignatureNonce(master, false);
|
||||
// Exchange pseudonyms, signed nonces, timestamps and transports
|
||||
// Exchange pseudonyms, signed nonces, and timestamps
|
||||
Author remoteAuthor;
|
||||
long remoteTimestamp;
|
||||
Map<TransportId, TransportProperties> remoteProps;
|
||||
boolean remoteReuseConnection;
|
||||
try {
|
||||
sendPseudonym(w, aliceNonce);
|
||||
sendTimestamp(w, localTimestamp);
|
||||
sendTransportProperties(w);
|
||||
sendConfirmation(w, reuseConnection);
|
||||
remoteAuthor = receivePseudonym(r, bobNonce);
|
||||
remoteTimestamp = receiveTimestamp(r);
|
||||
remoteProps = receiveTransportProperties(r);
|
||||
remoteReuseConnection = receiveConfirmation(r);
|
||||
// Close the outgoing stream and expect EOF on the incoming stream
|
||||
w.close();
|
||||
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
|
||||
long timestamp = Math.min(localTimestamp, remoteTimestamp);
|
||||
// Add the contact and store the transports
|
||||
// Add the contact
|
||||
try {
|
||||
addContact(remoteAuthor, remoteProps, master, timestamp, true);
|
||||
addContact(remoteAuthor, master, timestamp, true);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
tryToClose(conn, true);
|
||||
group.pseudonymExchangeFailed();
|
||||
return;
|
||||
}
|
||||
// Reuse the connection as a transport connection if both peers agree
|
||||
if (reuseConnection && remoteReuseConnection) reuseConnection(conn);
|
||||
else tryToClose(conn, false);
|
||||
// Reuse the connection as a transport connection
|
||||
reuseConnection(conn);
|
||||
// Pseudonym exchange succeeded
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " pseudonym exchange succeeded");
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.briarproject.invitation;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
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.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.property.TransportPropertyManager;
|
||||
import org.briarproject.api.sync.GroupFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.KeyManager;
|
||||
@@ -28,7 +25,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
@@ -47,17 +43,12 @@ class BobConnector extends Connector {
|
||||
StreamWriterFactory streamWriterFactory,
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionManager connectionManager,
|
||||
ContactManager contactManager,
|
||||
TransportPropertyManager transportPropertyManager, Clock clock,
|
||||
boolean reuseConnection, ConnectorGroup group, DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps,
|
||||
PseudoRandom random) {
|
||||
ContactManager contactManager, Clock clock, ConnectorGroup group,
|
||||
DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
|
||||
super(crypto, bdfReaderFactory, bdfWriterFactory, streamReaderFactory,
|
||||
streamWriterFactory, authorFactory, groupFactory,
|
||||
keyManager, connectionManager, contactManager,
|
||||
transportPropertyManager, clock, reuseConnection, group,
|
||||
plugin, localAuthor, localProps, random);
|
||||
streamWriterFactory, authorFactory, groupFactory, keyManager,
|
||||
connectionManager, contactManager, clock, group, plugin,
|
||||
localAuthor, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,20 +143,14 @@ class BobConnector extends Connector {
|
||||
// Derive the nonces
|
||||
byte[] aliceNonce = crypto.deriveSignatureNonce(master, true);
|
||||
byte[] bobNonce = crypto.deriveSignatureNonce(master, false);
|
||||
// Exchange pseudonyms, signed nonces, timestamps and transports
|
||||
// Exchange pseudonyms, signed nonces and timestamps
|
||||
Author remoteAuthor;
|
||||
long remoteTimestamp;
|
||||
Map<TransportId, TransportProperties> remoteProps;
|
||||
boolean remoteReuseConnection;
|
||||
try {
|
||||
remoteAuthor = receivePseudonym(r, aliceNonce);
|
||||
remoteTimestamp = receiveTimestamp(r);
|
||||
remoteProps = receiveTransportProperties(r);
|
||||
remoteReuseConnection = receiveConfirmation(r);
|
||||
sendPseudonym(w, bobNonce);
|
||||
sendTimestamp(w, localTimestamp);
|
||||
sendTransportProperties(w);
|
||||
sendConfirmation(w, reuseConnection);
|
||||
// Close the outgoing stream and expect EOF on the incoming stream
|
||||
w.close();
|
||||
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
|
||||
long timestamp = Math.min(localTimestamp, remoteTimestamp);
|
||||
// Add the contact and store the transports
|
||||
// Add the contact
|
||||
try {
|
||||
addContact(remoteAuthor, remoteProps, master, timestamp, false);
|
||||
addContact(remoteAuthor, master, timestamp, false);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
tryToClose(conn, true);
|
||||
group.pseudonymExchangeFailed();
|
||||
return;
|
||||
}
|
||||
// Reuse the connection as a transport connection if both peers agree
|
||||
if (reuseConnection && remoteReuseConnection) reuseConnection(conn);
|
||||
else tryToClose(conn, false);
|
||||
// Reuse the connection as a transport connection
|
||||
reuseConnection(conn);
|
||||
// Pseudonym exchange succeeded
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(pluginName + " pseudonym exchange succeeded");
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.briarproject.invitation;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
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.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.property.TransportPropertyManager;
|
||||
import org.briarproject.api.sync.GroupFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.KeyManager;
|
||||
@@ -33,16 +31,10 @@ import org.briarproject.api.transport.StreamWriterFactory;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
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_PUBLIC_KEY_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 ConnectionManager connectionManager;
|
||||
protected final ContactManager contactManager;
|
||||
protected final TransportPropertyManager transportPropertyManager;
|
||||
protected final Clock clock;
|
||||
protected final boolean reuseConnection;
|
||||
protected final ConnectorGroup group;
|
||||
protected final DuplexPlugin plugin;
|
||||
protected final LocalAuthor localAuthor;
|
||||
protected final Map<TransportId, TransportProperties> localProps;
|
||||
protected final PseudoRandom random;
|
||||
protected final String pluginName;
|
||||
|
||||
@@ -87,12 +76,8 @@ abstract class Connector extends Thread {
|
||||
StreamWriterFactory streamWriterFactory,
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionManager connectionManager,
|
||||
ContactManager contactManager,
|
||||
TransportPropertyManager transportPropertyManager, Clock clock,
|
||||
boolean reuseConnection, ConnectorGroup group, DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps,
|
||||
PseudoRandom random) {
|
||||
ContactManager contactManager, Clock clock, ConnectorGroup group,
|
||||
DuplexPlugin plugin, LocalAuthor localAuthor, PseudoRandom random) {
|
||||
super("Connector");
|
||||
this.crypto = crypto;
|
||||
this.bdfReaderFactory = bdfReaderFactory;
|
||||
@@ -104,13 +89,10 @@ abstract class Connector extends Thread {
|
||||
this.keyManager = keyManager;
|
||||
this.connectionManager = connectionManager;
|
||||
this.contactManager = contactManager;
|
||||
this.transportPropertyManager = transportPropertyManager;
|
||||
this.clock = clock;
|
||||
this.reuseConnection = reuseConnection;
|
||||
this.group = group;
|
||||
this.plugin = plugin;
|
||||
this.localAuthor = localAuthor;
|
||||
this.localProps = localProps;
|
||||
this.random = random;
|
||||
pluginName = plugin.getClass().getName();
|
||||
keyPair = crypto.generateAgreementKeyPair();
|
||||
@@ -233,57 +215,14 @@ abstract class Connector extends Thread {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
protected void sendTransportProperties(BdfWriter w) throws IOException {
|
||||
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,
|
||||
protected ContactId addContact(Author remoteAuthor, SecretKey master,
|
||||
long timestamp, boolean alice) throws DbException {
|
||||
// Add the contact to the database
|
||||
contactId = contactManager.addContact(remoteAuthor,
|
||||
localAuthor.getId());
|
||||
// Store the remote transport properties
|
||||
transportPropertyManager.setRemoteProperties(contactId, remoteProps);
|
||||
// Derive transport keys for each transport shared with the contact
|
||||
keyManager.addContact(contactId, remoteProps.keySet(), master,
|
||||
timestamp, alice);
|
||||
// Derive transport keys
|
||||
keyManager.addContact(contactId, master, timestamp, alice);
|
||||
return contactId;
|
||||
}
|
||||
|
||||
protected void tryToClose(DuplexTransportConnection conn,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.briarproject.invitation;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
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.PluginManager;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.property.TransportPropertyManager;
|
||||
import org.briarproject.api.sync.GroupFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.KeyManager;
|
||||
@@ -28,7 +25,6 @@ import org.briarproject.api.transport.StreamWriterFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -57,12 +53,10 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
||||
private final ConnectionManager connectionManager;
|
||||
private final IdentityManager identityManager;
|
||||
private final ContactManager contactManager;
|
||||
private final TransportPropertyManager transportPropertyManager;
|
||||
private final Clock clock;
|
||||
private final PluginManager pluginManager;
|
||||
private final AuthorId localAuthorId;
|
||||
private final int localInvitationCode, remoteInvitationCode;
|
||||
private final boolean reuseConnection;
|
||||
private final Collection<InvitationListener> listeners;
|
||||
private final AtomicBoolean connected;
|
||||
private final CountDownLatch localConfirmationLatch;
|
||||
@@ -83,10 +77,8 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionManager connectionManager,
|
||||
IdentityManager identityManager, ContactManager contactManager,
|
||||
TransportPropertyManager transportPropertyManager, Clock clock,
|
||||
PluginManager pluginManager, AuthorId localAuthorId,
|
||||
int localInvitationCode, int remoteInvitationCode,
|
||||
boolean reuseConnection) {
|
||||
Clock clock, PluginManager pluginManager, AuthorId localAuthorId,
|
||||
int localInvitationCode, int remoteInvitationCode) {
|
||||
super("ConnectorGroup");
|
||||
this.crypto = crypto;
|
||||
this.bdfReaderFactory = bdfReaderFactory;
|
||||
@@ -99,13 +91,11 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
||||
this.connectionManager = connectionManager;
|
||||
this.identityManager = identityManager;
|
||||
this.contactManager = contactManager;
|
||||
this.transportPropertyManager = transportPropertyManager;
|
||||
this.clock = clock;
|
||||
this.pluginManager = pluginManager;
|
||||
this.localAuthorId = localAuthorId;
|
||||
this.localInvitationCode = localInvitationCode;
|
||||
this.remoteInvitationCode = remoteInvitationCode;
|
||||
this.reuseConnection = reuseConnection;
|
||||
listeners = new CopyOnWriteArrayList<InvitationListener>();
|
||||
connected = new AtomicBoolean(false);
|
||||
localConfirmationLatch = new CountDownLatch(1);
|
||||
@@ -136,11 +126,9 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
||||
@Override
|
||||
public void run() {
|
||||
LocalAuthor localAuthor;
|
||||
Map<TransportId, TransportProperties> localProps;
|
||||
// Load the local pseudonym and transport properties
|
||||
// Load the local pseudonym
|
||||
try {
|
||||
localAuthor = identityManager.getLocalAuthor(localAuthorId);
|
||||
localProps = transportPropertyManager.getLocalProperties();
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
lock.lock();
|
||||
@@ -157,15 +145,13 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
||||
// Alice is the party with the smaller invitation code
|
||||
if (localInvitationCode < remoteInvitationCode) {
|
||||
for (DuplexPlugin plugin : pluginManager.getInvitationPlugins()) {
|
||||
Connector c = createAliceConnector(plugin, localAuthor,
|
||||
localProps);
|
||||
Connector c = createAliceConnector(plugin, localAuthor);
|
||||
connectors.add(c);
|
||||
c.start();
|
||||
}
|
||||
} else {
|
||||
for (DuplexPlugin plugin: pluginManager.getInvitationPlugins()) {
|
||||
Connector c = createBobConnector(plugin, localAuthor,
|
||||
localProps);
|
||||
Connector c = createBobConnector(plugin, localAuthor);
|
||||
connectors.add(c);
|
||||
c.start();
|
||||
}
|
||||
@@ -190,27 +176,23 @@ class ConnectorGroup extends Thread implements InvitationTask {
|
||||
}
|
||||
|
||||
private Connector createAliceConnector(DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps) {
|
||||
LocalAuthor localAuthor) {
|
||||
PseudoRandom random = crypto.getPseudoRandom(localInvitationCode,
|
||||
remoteInvitationCode);
|
||||
return new AliceConnector(crypto, bdfReaderFactory, bdfWriterFactory,
|
||||
streamReaderFactory, streamWriterFactory, authorFactory,
|
||||
groupFactory, keyManager, connectionManager, contactManager,
|
||||
transportPropertyManager, clock, reuseConnection, this, plugin,
|
||||
localAuthor, localProps, random);
|
||||
clock, this, plugin, localAuthor, random);
|
||||
}
|
||||
|
||||
private Connector createBobConnector(DuplexPlugin plugin,
|
||||
LocalAuthor localAuthor,
|
||||
Map<TransportId, TransportProperties> localProps) {
|
||||
LocalAuthor localAuthor) {
|
||||
PseudoRandom random = crypto.getPseudoRandom(remoteInvitationCode,
|
||||
localInvitationCode);
|
||||
return new BobConnector(crypto, bdfReaderFactory, bdfWriterFactory,
|
||||
streamReaderFactory, streamWriterFactory, authorFactory,
|
||||
groupFactory, keyManager, connectionManager, contactManager,
|
||||
transportPropertyManager, clock, reuseConnection, this, plugin,
|
||||
localAuthor, localProps, random);
|
||||
clock, this, plugin, localAuthor, random);
|
||||
}
|
||||
|
||||
public void localConfirmationSucceeded() {
|
||||
|
||||
@@ -11,7 +11,6 @@ import org.briarproject.api.invitation.InvitationTask;
|
||||
import org.briarproject.api.invitation.InvitationTaskFactory;
|
||||
import org.briarproject.api.plugins.ConnectionManager;
|
||||
import org.briarproject.api.plugins.PluginManager;
|
||||
import org.briarproject.api.property.TransportPropertyManager;
|
||||
import org.briarproject.api.sync.GroupFactory;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.api.transport.KeyManager;
|
||||
@@ -33,7 +32,6 @@ class InvitationTaskFactoryImpl implements InvitationTaskFactory {
|
||||
private final ConnectionManager connectionManager;
|
||||
private final IdentityManager identityManager;
|
||||
private final ContactManager contactManager;
|
||||
private final TransportPropertyManager transportPropertyManager;
|
||||
private final Clock clock;
|
||||
private final PluginManager pluginManager;
|
||||
|
||||
@@ -45,7 +43,6 @@ class InvitationTaskFactoryImpl implements InvitationTaskFactory {
|
||||
AuthorFactory authorFactory, GroupFactory groupFactory,
|
||||
KeyManager keyManager, ConnectionManager connectionManager,
|
||||
IdentityManager identityManager, ContactManager contactManager,
|
||||
TransportPropertyManager transportPropertyManager,
|
||||
Clock clock, PluginManager pluginManager) {
|
||||
this.crypto = crypto;
|
||||
this.bdfReaderFactory = bdfReaderFactory;
|
||||
@@ -58,17 +55,16 @@ class InvitationTaskFactoryImpl implements InvitationTaskFactory {
|
||||
this.connectionManager = connectionManager;
|
||||
this.identityManager = identityManager;
|
||||
this.contactManager = contactManager;
|
||||
this.transportPropertyManager = transportPropertyManager;
|
||||
this.clock = clock;
|
||||
this.pluginManager = pluginManager;
|
||||
}
|
||||
|
||||
public InvitationTask createTask(AuthorId localAuthorId, int localCode,
|
||||
int remoteCode, boolean reuseConnection) {
|
||||
int remoteCode) {
|
||||
return new ConnectorGroup(crypto, bdfReaderFactory, bdfWriterFactory,
|
||||
streamReaderFactory, streamWriterFactory, authorFactory,
|
||||
groupFactory, keyManager, connectionManager, identityManager,
|
||||
contactManager, transportPropertyManager, clock, pluginManager,
|
||||
localAuthorId, localCode, remoteCode, reuseConnection);
|
||||
contactManager, clock, pluginManager, localAuthorId, localCode,
|
||||
remoteCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package org.briarproject.lifecycle;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
||||
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.DB_ERROR;
|
||||
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR;
|
||||
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.ShutdownEvent;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
import org.briarproject.api.system.Clock;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
@@ -17,13 +18,12 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.ShutdownEvent;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
||||
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.DB_ERROR;
|
||||
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR;
|
||||
import static org.briarproject.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||
|
||||
class LifecycleManagerImpl implements LifecycleManager {
|
||||
|
||||
@@ -98,9 +98,6 @@ class LifecycleManagerImpl implements LifecycleManager {
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
return DB_ERROR;
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
return DB_ERROR;
|
||||
} finally {
|
||||
startStopSemaphore.release();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import org.briarproject.api.system.Clock;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import static org.briarproject.messaging.MessagingManagerImpl.CLIENT_ID;
|
||||
|
||||
public class MessagingModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
@@ -22,14 +24,11 @@ public class MessagingModule extends AbstractModule {
|
||||
|
||||
@Provides @Singleton
|
||||
PrivateMessageValidator getValidator(ValidationManager validationManager,
|
||||
MessagingManager messagingManager,
|
||||
BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder,
|
||||
Clock clock) {
|
||||
PrivateMessageValidator validator = new PrivateMessageValidator(
|
||||
bdfReaderFactory, metadataEncoder, clock);
|
||||
validationManager.registerMessageValidator(
|
||||
messagingManager.getClientId(),
|
||||
validator);
|
||||
validationManager.registerMessageValidator(CLIENT_ID, validator);
|
||||
return validator;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,8 +73,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
ioExecutor.execute(new ManageOutgoingDuplexConnection(c, t, d));
|
||||
}
|
||||
|
||||
private byte[] readTag(TransportId t, TransportConnectionReader r)
|
||||
throws IOException {
|
||||
private byte[] readTag(TransportConnectionReader r) throws IOException {
|
||||
// Read the tag
|
||||
byte[] tag = new byte[TAG_LENGTH];
|
||||
InputStream in = r.getInputStream();
|
||||
@@ -128,7 +127,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
// Read and recognise the tag
|
||||
StreamContext ctx;
|
||||
try {
|
||||
byte[] tag = readTag(transportId, reader);
|
||||
byte[] tag = readTag(reader);
|
||||
ctx = keyManager.getStreamContext(transportId, tag);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
@@ -228,7 +227,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
// Read and recognise the tag
|
||||
StreamContext ctx;
|
||||
try {
|
||||
byte[] tag = readTag(transportId, reader);
|
||||
byte[] tag = readTag(reader);
|
||||
ctx = keyManager.getStreamContext(transportId, tag);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
@@ -353,7 +352,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
// Read and recognise the tag
|
||||
StreamContext ctx;
|
||||
try {
|
||||
byte[] tag = readTag(transportId, reader);
|
||||
byte[] tag = readTag(reader);
|
||||
ctx = keyManager.getStreamContext(transportId, tag);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package org.briarproject.plugins;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
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;
|
||||
@@ -26,7 +24,9 @@ import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
|
||||
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.ui.UiCallback;
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
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.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -8,10 +12,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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 {
|
||||
|
||||
static final TransportId ID = new TransportId("lan");
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.briarproject.plugins.tcp;
|
||||
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
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.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -8,10 +12,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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 {
|
||||
|
||||
static final TransportId ID = new TransportId("wan");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package org.briarproject.settings;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.api.settings.SettingsManager;
|
||||
|
||||
class SettingsManagerImpl implements SettingsManager {
|
||||
|
||||
@@ -9,13 +9,11 @@ import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
|
||||
import org.briarproject.api.event.LocalTransportsUpdatedEvent;
|
||||
import org.briarproject.api.event.MessageRequestedEvent;
|
||||
import org.briarproject.api.event.MessageToAckEvent;
|
||||
import org.briarproject.api.event.MessageToRequestEvent;
|
||||
import org.briarproject.api.event.MessageValidatedEvent;
|
||||
import org.briarproject.api.event.RemoteSubscriptionsUpdatedEvent;
|
||||
import org.briarproject.api.event.RemoteTransportsUpdatedEvent;
|
||||
import org.briarproject.api.event.ShutdownEvent;
|
||||
import org.briarproject.api.event.TransportRemovedEvent;
|
||||
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.SubscriptionUpdate;
|
||||
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 java.io.IOException;
|
||||
@@ -91,8 +87,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
eventBus.addListener(this);
|
||||
try {
|
||||
// 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 GenerateSubscriptionUpdate());
|
||||
dbExecutor.execute(new GenerateAck());
|
||||
@@ -123,7 +117,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
now = clock.currentTimeMillis();
|
||||
if (now >= nextRetxQuery) {
|
||||
// Check for retransmittable packets
|
||||
dbExecutor.execute(new GenerateTransportUpdates());
|
||||
dbExecutor.execute(new GenerateSubscriptionUpdate());
|
||||
dbExecutor.execute(new GenerateBatch());
|
||||
dbExecutor.execute(new GenerateOffer());
|
||||
@@ -171,8 +164,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
dbExecutor.execute(new GenerateSubscriptionUpdate());
|
||||
dbExecutor.execute(new GenerateOffer());
|
||||
}
|
||||
} else if (e instanceof LocalTransportsUpdatedEvent) {
|
||||
dbExecutor.execute(new GenerateTransportUpdates());
|
||||
} else if (e instanceof MessageRequestedEvent) {
|
||||
if (((MessageRequestedEvent) e).getContactId().equals(contactId))
|
||||
dbExecutor.execute(new GenerateBatch());
|
||||
@@ -189,11 +180,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
dbExecutor.execute(new GenerateSubscriptionAck());
|
||||
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) {
|
||||
interrupt();
|
||||
} else if (e instanceof TransportRemovedEvent) {
|
||||
@@ -414,76 +400,4 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ import org.briarproject.api.sync.Request;
|
||||
import org.briarproject.api.sync.SubscriptionAck;
|
||||
import org.briarproject.api.sync.SubscriptionUpdate;
|
||||
import org.briarproject.api.sync.SyncSession;
|
||||
import org.briarproject.api.sync.TransportAck;
|
||||
import org.briarproject.api.sync.TransportUpdate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -77,12 +75,6 @@ class IncomingSession implements SyncSession, EventListener {
|
||||
} else if (packetReader.hasSubscriptionUpdate()) {
|
||||
SubscriptionUpdate u = packetReader.readSubscriptionUpdate();
|
||||
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 {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package org.briarproject.sync;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.UniqueId;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
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.SubscriptionAck;
|
||||
import org.briarproject.api.sync.SubscriptionUpdate;
|
||||
import org.briarproject.api.sync.TransportAck;
|
||||
import org.briarproject.api.sync.TransportUpdate;
|
||||
import org.briarproject.util.ByteUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -26,21 +22,14 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
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.MESSAGE;
|
||||
import static org.briarproject.api.sync.PacketTypes.OFFER;
|
||||
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_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.MESSAGE_HEADER_LENGTH;
|
||||
import static org.briarproject.api.sync.SyncConstants.PACKET_HEADER_LENGTH;
|
||||
@@ -205,66 +194,4 @@ class PacketReaderImpl implements PacketReader {
|
||||
state = State.BUFFER_EMPTY;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import org.briarproject.api.sync.PacketWriter;
|
||||
import org.briarproject.api.sync.Request;
|
||||
import org.briarproject.api.sync.SubscriptionAck;
|
||||
import org.briarproject.api.sync.SubscriptionUpdate;
|
||||
import org.briarproject.api.sync.TransportAck;
|
||||
import org.briarproject.api.sync.TransportUpdate;
|
||||
import org.briarproject.util.ByteUtils;
|
||||
|
||||
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.SUBSCRIPTION_ACK;
|
||||
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.PACKET_HEADER_LENGTH;
|
||||
import static org.briarproject.api.sync.SyncConstants.PROTOCOL_VERSION;
|
||||
@@ -125,27 +121,6 @@ class PacketWriterImpl implements PacketWriter {
|
||||
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 {
|
||||
out.flush();
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@ import org.briarproject.api.sync.PacketWriter;
|
||||
import org.briarproject.api.sync.SubscriptionAck;
|
||||
import org.briarproject.api.sync.SubscriptionUpdate;
|
||||
import org.briarproject.api.sync.SyncSession;
|
||||
import org.briarproject.api.sync.TransportAck;
|
||||
import org.briarproject.api.sync.TransportUpdate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
@@ -68,7 +66,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
||||
this.transportId = transportId;
|
||||
this.maxLatency = maxLatency;
|
||||
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>>();
|
||||
}
|
||||
|
||||
@@ -76,8 +74,6 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
||||
eventBus.addListener(this);
|
||||
try {
|
||||
// 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 GenerateSubscriptionUpdate());
|
||||
dbExecutor.execute(new GenerateAck());
|
||||
@@ -264,78 +260,4 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import org.briarproject.api.system.Timer;
|
||||
import org.briarproject.api.transport.KeyManager;
|
||||
import org.briarproject.api.transport.StreamContext;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -71,12 +70,10 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addContact(ContactId c, Collection<TransportId> transports,
|
||||
SecretKey master, long timestamp, boolean alice) {
|
||||
for (TransportId t : transports) {
|
||||
TransportKeyManager m = managers.get(t);
|
||||
if (m != null) m.addContact(c, master, timestamp, alice);
|
||||
}
|
||||
public void addContact(ContactId c, SecretKey master, long timestamp,
|
||||
boolean alice) {
|
||||
for (TransportKeyManager m : managers.values())
|
||||
m.addContact(c, master, timestamp, alice);
|
||||
}
|
||||
|
||||
public StreamContext getStreamContext(ContactId c, TransportId t) {
|
||||
|
||||
@@ -65,7 +65,8 @@ public class StringUtils {
|
||||
/** Converts the given hex string to a byte array. */
|
||||
public static byte[] fromHexString(String hex) {
|
||||
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];
|
||||
for (int i = 0, j = 0; i < len; i += 2, j++) {
|
||||
int high = hexDigitToInt(hex.charAt(i));
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package org.briarproject.plugins.bluetooth;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.util.LatchedReference;
|
||||
import org.briarproject.util.OsUtils;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.briarproject.plugins.modem;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
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.DuplexPluginCallback;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
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.Request;
|
||||
import org.briarproject.api.sync.SubscriptionUpdate;
|
||||
import org.briarproject.api.sync.TransportUpdate;
|
||||
import org.briarproject.api.transport.StreamContext;
|
||||
import org.briarproject.api.transport.StreamReaderFactory;
|
||||
import org.briarproject.api.transport.StreamWriterFactory;
|
||||
@@ -56,12 +54,11 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
||||
private final PacketWriterFactory packetWriterFactory;
|
||||
|
||||
private final ContactId contactId;
|
||||
private final TransportId transportId;
|
||||
private final SecretKey tagKey, headerKey;
|
||||
private final Group group;
|
||||
private final Message message, message1;
|
||||
private final Collection<MessageId> messageIds;
|
||||
private final TransportId transportId;
|
||||
private final TransportProperties transportProperties;
|
||||
|
||||
public ProtocolIntegrationTest() throws Exception {
|
||||
Injector i = Guice.createInjector(new TestDatabaseModule(),
|
||||
@@ -74,6 +71,7 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
||||
packetReaderFactory = i.getInstance(PacketReaderFactory.class);
|
||||
packetWriterFactory = i.getInstance(PacketWriterFactory.class);
|
||||
contactId = new ContactId(234);
|
||||
transportId = new TransportId("id");
|
||||
// Create the transport keys
|
||||
tagKey = TestUtils.createSecretKey();
|
||||
headerKey = TestUtils.createSecretKey();
|
||||
@@ -91,10 +89,6 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
||||
message1 = messageFactory.createMessage(group.getId(), timestamp,
|
||||
messageBody.getBytes("UTF-8"));
|
||||
messageIds = Arrays.asList(message.getId(), message1.getId());
|
||||
// Create some transport properties
|
||||
transportId = new TransportId("id");
|
||||
transportProperties = new TransportProperties(Collections.singletonMap(
|
||||
"bar", "baz"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -124,10 +118,6 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
||||
Collections.singletonList(group), 1);
|
||||
packetWriter.writeSubscriptionUpdate(su);
|
||||
|
||||
TransportUpdate tu = new TransportUpdate(transportId,
|
||||
transportProperties, 1);
|
||||
packetWriter.writeTransportUpdate(tu);
|
||||
|
||||
streamWriter.flush();
|
||||
return out.toByteArray();
|
||||
}
|
||||
@@ -174,13 +164,6 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
||||
assertEquals(Collections.singletonList(group), su.getGroups());
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.briarproject.db;
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.TestUtils;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
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.event.EventBus;
|
||||
import org.briarproject.api.event.LocalSubscriptionsUpdatedEvent;
|
||||
import org.briarproject.api.event.LocalTransportsUpdatedEvent;
|
||||
import org.briarproject.api.event.MessageAddedEvent;
|
||||
import org.briarproject.api.event.MessageRequestedEvent;
|
||||
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.SubscriptionAck;
|
||||
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.OutgoingKeys;
|
||||
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.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@@ -80,7 +75,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
private final Message message;
|
||||
private final Metadata metadata;
|
||||
private final TransportId transportId;
|
||||
private final TransportProperties transportProperties;
|
||||
private final int maxLatency;
|
||||
private final ContactId contactId;
|
||||
private final Contact contact;
|
||||
@@ -88,7 +82,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
public DatabaseComponentImplTest() {
|
||||
clientId = new ClientId(TestUtils.getRandomId());
|
||||
groupId = new GroupId(TestUtils.getRandomId());
|
||||
ClientId clientId = new ClientId(TestUtils.getRandomId());
|
||||
byte[] descriptor = new byte[MAX_GROUP_DESCRIPTOR_LENGTH];
|
||||
group = new Group(groupId, clientId, descriptor);
|
||||
authorId = new AuthorId(TestUtils.getRandomId());
|
||||
@@ -106,8 +99,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
metadata = new Metadata();
|
||||
metadata.put("foo", new byte[] {'b', 'a', 'r'});
|
||||
transportId = new TransportId("id");
|
||||
transportProperties = new TransportProperties(Collections.singletonMap(
|
||||
"bar", "baz"));
|
||||
maxLatency = Integer.MAX_VALUE;
|
||||
contactId = new ContactId(234);
|
||||
contact = new Contact(contactId, author, localAuthorId,
|
||||
@@ -128,9 +119,9 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
final EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
exactly(10).of(database).startTransaction();
|
||||
exactly(9).of(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
exactly(10).of(database).commitTransaction(txn);
|
||||
exactly(9).of(database).commitTransaction(txn);
|
||||
// open()
|
||||
oneOf(database).open();
|
||||
will(returnValue(false));
|
||||
@@ -150,9 +141,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
// getContacts()
|
||||
oneOf(database).getContacts(txn);
|
||||
will(returnValue(Collections.singletonList(contact)));
|
||||
// getRemoteProperties()
|
||||
oneOf(database).getRemoteProperties(txn, transportId);
|
||||
will(returnValue(Collections.emptyMap()));
|
||||
// addGroup()
|
||||
oneOf(database).containsGroup(txn, groupId);
|
||||
will(returnValue(false));
|
||||
@@ -194,8 +182,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
db.addLocalAuthor(localAuthor);
|
||||
assertEquals(contactId, db.addContact(author, localAuthorId));
|
||||
assertEquals(Collections.singletonList(contact), db.getContacts());
|
||||
assertEquals(Collections.emptyMap(),
|
||||
db.getRemoteProperties(transportId));
|
||||
db.addGroup(group); // First time - listeners called
|
||||
db.addGroup(group); // Second time - not called
|
||||
assertEquals(Collections.singletonList(group), db.getGroups(clientId));
|
||||
@@ -310,11 +296,11 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
final EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
// 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));
|
||||
exactly(21).of(database).containsContact(txn, contactId);
|
||||
exactly(17).of(database).containsContact(txn, contactId);
|
||||
will(returnValue(false));
|
||||
exactly(21).of(database).abortTransaction(txn);
|
||||
exactly(17).of(database).abortTransaction(txn);
|
||||
}});
|
||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||
shutdown);
|
||||
@@ -361,20 +347,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
// Expected
|
||||
}
|
||||
|
||||
try {
|
||||
db.generateTransportAcks(contactId);
|
||||
fail();
|
||||
} catch (NoSuchContactException expected) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
try {
|
||||
db.generateTransportUpdates(contactId, 123);
|
||||
fail();
|
||||
} catch (NoSuchContactException expected) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
try {
|
||||
db.getContact(contactId);
|
||||
fail();
|
||||
@@ -443,23 +415,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
// 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 {
|
||||
db.removeContact(contactId);
|
||||
fail();
|
||||
@@ -677,13 +632,13 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
will(returnValue(contactId));
|
||||
oneOf(database).commitTransaction(txn);
|
||||
// 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));
|
||||
exactly(2).of(database).containsContact(txn, contactId);
|
||||
will(returnValue(true));
|
||||
exactly(6).of(database).containsTransport(txn, transportId);
|
||||
exactly(4).of(database).containsTransport(txn, transportId);
|
||||
will(returnValue(false));
|
||||
exactly(6).of(database).abortTransaction(txn);
|
||||
exactly(4).of(database).abortTransaction(txn);
|
||||
}});
|
||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||
shutdown);
|
||||
@@ -691,13 +646,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
db.addLocalAuthor(localAuthor);
|
||||
assertEquals(contactId, db.addContact(author, localAuthorId));
|
||||
|
||||
try {
|
||||
db.getLocalProperties(transportId);
|
||||
fail();
|
||||
} catch (NoSuchTransportException expected) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
try {
|
||||
db.getTransportKeys(transportId);
|
||||
fail();
|
||||
@@ -705,13 +653,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
// Expected
|
||||
}
|
||||
|
||||
try {
|
||||
db.mergeLocalProperties(transportId, new TransportProperties());
|
||||
fail();
|
||||
} catch (NoSuchTransportException expected) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
try {
|
||||
db.incrementStreamCounter(contactId, transportId, 0);
|
||||
fail();
|
||||
@@ -952,62 +893,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
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
|
||||
public void testReceiveAck() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@@ -1253,116 +1138,6 @@ public class DatabaseComponentImplTest extends BriarTestCase {
|
||||
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
|
||||
public void testChangingVisibilityCallsListeners() throws Exception {
|
||||
final ContactId contactId1 = new ContactId(123);
|
||||
|
||||
@@ -3,9 +3,7 @@ package org.briarproject.db;
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.TestDatabaseConfig;
|
||||
import org.briarproject.TestUtils;
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
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.AuthorId;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.Group;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
@@ -29,6 +28,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.SecureRandom;
|
||||
import java.sql.Connection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -137,8 +137,6 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db = open(true);
|
||||
txn = db.startTransaction();
|
||||
assertFalse(db.containsContact(txn, contactId));
|
||||
assertEquals(Collections.emptyMap(),
|
||||
db.getRemoteProperties(txn, transportId));
|
||||
assertFalse(db.containsGroup(txn, groupId));
|
||||
assertFalse(db.containsMessage(txn, messageId));
|
||||
db.commitTransaction(txn);
|
||||
@@ -502,71 +500,6 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
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
|
||||
public void testUpdateSettings() throws Exception {
|
||||
Database<Connection> db = open(false);
|
||||
@@ -597,42 +530,6 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
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
|
||||
public void testContainsVisibleMessageRequiresMessageInDatabase()
|
||||
throws Exception {
|
||||
@@ -1225,7 +1122,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
|
||||
private Database<Connection> open(boolean resume) throws Exception {
|
||||
Database<Connection> db = new H2Database(new TestDatabaseConfig(testDir,
|
||||
MAX_SIZE), new SystemClock());
|
||||
MAX_SIZE), new SecureRandom(), new SystemClock());
|
||||
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
||||
db.open();
|
||||
return db;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.briarproject.plugins;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
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.util.Map;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.briarproject.plugins;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
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.concurrent.CountDownLatch;
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
|
||||
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.ui.UiCallback;
|
||||
import org.briarproject.system.SystemClock;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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.properties.TransportProperties;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.plugins.DuplexClientTest;
|
||||
import org.briarproject.system.SystemClock;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.briarproject.plugins.bluetooth;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.plugins.DuplexServerTest;
|
||||
import org.briarproject.system.SystemClock;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.briarproject.plugins.modem;
|
||||
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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.properties.TransportProperties;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.plugins.DuplexClientTest;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package org.briarproject.plugins.tcp;
|
||||
|
||||
import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.briarproject.plugins.tcp;
|
||||
|
||||
import org.briarproject.api.Settings;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.briarproject.api.settings.Settings;
|
||||
import org.briarproject.plugins.DuplexServerTest;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import org.briarproject.TestDatabaseModule;
|
||||
import org.briarproject.TestLifecycleModule;
|
||||
import org.briarproject.TestSystemModule;
|
||||
import org.briarproject.TestUtils;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.TransportProperties;
|
||||
import org.briarproject.api.UniqueId;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
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.Request;
|
||||
import org.briarproject.api.sync.SubscriptionUpdate;
|
||||
import org.briarproject.api.sync.TransportUpdate;
|
||||
import org.briarproject.contact.ContactModule;
|
||||
import org.briarproject.crypto.CryptoModule;
|
||||
import org.briarproject.data.DataModule;
|
||||
@@ -50,9 +47,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
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.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||
@@ -194,27 +188,6 @@ public class ConstantsTest extends BriarTestCase {
|
||||
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
|
||||
public void testGroupsFitIntoSubscriptionUpdate() throws Exception {
|
||||
// Create the maximum number of maximum-length groups
|
||||
|
||||
@@ -54,7 +54,6 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_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]);
|
||||
ContactId contactId = contactManager.addContact(bobAuthor, aliceId);
|
||||
// Derive and store the transport keys
|
||||
keyManager.addContact(contactId, Collections.singletonList(transportId),
|
||||
master, timestamp, true);
|
||||
keyManager.addContact(contactId, master, timestamp, true);
|
||||
|
||||
// Send Bob a message
|
||||
GroupId groupId = messagingManager.getConversationId(contactId);
|
||||
@@ -198,8 +196,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
|
||||
new byte[MAX_PUBLIC_KEY_LENGTH]);
|
||||
ContactId contactId = contactManager.addContact(aliceAuthor, bobId);
|
||||
// Derive and store the transport keys
|
||||
keyManager.addContact(contactId, Collections.singletonList(transportId),
|
||||
master, timestamp, false);
|
||||
keyManager.addContact(contactId, master, timestamp, false);
|
||||
|
||||
// Set up an event listener
|
||||
MessageListener listener = new MessageListener();
|
||||
|
||||
@@ -52,12 +52,6 @@ public class SimplexOutgoingSessionTest extends BriarTestCase {
|
||||
context.checking(new Expectations() {{
|
||||
// Add listener
|
||||
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
|
||||
oneOf(db).generateSubscriptionAck(contactId);
|
||||
will(returnValue(null));
|
||||
@@ -92,12 +86,6 @@ public class SimplexOutgoingSessionTest extends BriarTestCase {
|
||||
context.checking(new Expectations() {{
|
||||
// Add listener
|
||||
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
|
||||
oneOf(db).generateSubscriptionAck(contactId);
|
||||
will(returnValue(null));
|
||||
|
||||
Reference in New Issue
Block a user