Commit 3a837b3c authored by akwizgran's avatar akwizgran

Resolve merge conflicts.

# Conflicts:
#   briar-android/src/main/res/values/strings.xml
parents 9c20e6b3 ac259786
Pipeline #3572 passed with stage
in 8 minutes and 33 seconds
......@@ -29,6 +29,7 @@ import org.briarproject.bramble.api.transport.TransportKeySet;
import org.briarproject.bramble.api.transport.TransportKeys;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
......@@ -427,6 +428,13 @@ public interface DatabaseComponent extends TransactionManager {
*/
Settings getSettings(Transaction txn, String namespace) throws DbException;
/**
* Returns the versions of the sync protocol supported by the given contact.
* <p/>
* Read-only.
*/
List<Byte> getSyncVersions(Transaction txn, ContactId c) throws DbException;
/**
* Returns all transport keys for the given transport.
* <p/>
......@@ -579,6 +587,12 @@ public interface DatabaseComponent extends TransactionManager {
void setReorderingWindow(Transaction txn, KeySetId k, TransportId t,
long timePeriod, long base, byte[] bitmap) throws DbException;
/**
* Sets the versions of the sync protocol supported by the given contact.
*/
void setSyncVersions(Transaction txn, ContactId c, List<Byte> supported)
throws DbException;
/**
* Marks the given transport keys as usable for outgoing streams.
*/
......
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import javax.annotation.concurrent.Immutable;
/**
* A record acknowledging receipt of one or more {@link Message Messages}.
*/
@Immutable
@NotNullByDefault
public class Ack {
private final Collection<MessageId> acked;
......
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
@Immutable
@NotNullByDefault
public class Message {
/**
......
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import javax.annotation.concurrent.Immutable;
/**
* A record offering the recipient one or more {@link Message Messages}.
*/
@Immutable
@NotNullByDefault
public class Offer {
private final Collection<MessageId> offered;
......
......@@ -9,5 +9,5 @@ public interface RecordTypes {
byte MESSAGE = 1;
byte OFFER = 2;
byte REQUEST = 3;
byte VERSIONS = 4;
}
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import javax.annotation.concurrent.Immutable;
/**
* A record requesting one or more {@link Message Messages} from the recipient.
*/
@Immutable
@NotNullByDefault
public class Request {
private final Collection<MessageId> requested;
......
......@@ -2,6 +2,9 @@ package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.UniqueId;
import java.util.List;
import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
public interface SyncConstants {
......@@ -11,6 +14,11 @@ public interface SyncConstants {
*/
byte PROTOCOL_VERSION = 0;
/**
* The versions of the sync protocol this peer supports.
*/
List<Byte> SUPPORTED_VERSIONS = singletonList(PROTOCOL_VERSION);
/**
* The maximum length of a group descriptor in bytes.
*/
......@@ -35,4 +43,10 @@ public interface SyncConstants {
* The maximum number of message IDs in an ack, offer or request record.
*/
int MAX_MESSAGE_IDS = MAX_RECORD_PAYLOAD_BYTES / UniqueId.LENGTH;
/**
* The maximum number of versions of the sync protocol a peer may support
* simultaneously.
*/
int MAX_SUPPORTED_VERSIONS = 10;
}
......@@ -25,4 +25,7 @@ public interface SyncRecordReader {
Request readRequest() throws IOException;
boolean hasVersions() throws IOException;
Versions readVersions() throws IOException;
}
......@@ -15,5 +15,7 @@ public interface SyncRecordWriter {
void writeRequest(Request r) throws IOException;
void writeVersions(Versions v) throws IOException;
void flush() throws IOException;
}
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import javax.annotation.concurrent.Immutable;
/**
* A record telling the recipient which versions of the sync protocol the
* sender supports.
*/
@Immutable
@NotNullByDefault
public class Versions {
private final List<Byte> supported;
public Versions(List<Byte> supported) {
this.supported = supported;
}
public List<Byte> getSupportedVersions() {
return supported;
}
}
package org.briarproject.bramble.api.sync.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when the versions of the sync protocol supported
* by a contact are updated.
*/
@Immutable
@NotNullByDefault
public class SyncVersionsUpdatedEvent extends Event {
private final ContactId contactId;
private final List<Byte> supported;
public SyncVersionsUpdatedEvent(ContactId contactId, List<Byte> supported) {
this.contactId = contactId;
this.supported = supported;
}
public ContactId getContactId() {
return contactId;
}
public List<Byte> getSupportedVersions() {
return supported;
}
}
......@@ -33,6 +33,7 @@ import org.briarproject.bramble.api.transport.TransportKeySet;
import org.briarproject.bramble.api.transport.TransportKeys;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
......@@ -528,6 +529,13 @@ interface Database<T> {
*/
Settings getSettings(T txn, String namespace) throws DbException;
/**
* Returns the versions of the sync protocol supported by the given contact.
* <p/>
* Read-only.
*/
List<Byte> getSyncVersions(T txn, ContactId c) throws DbException;
/**
* Returns all transport keys for the given transport.
* <p/>
......@@ -700,6 +708,12 @@ interface Database<T> {
void setReorderingWindow(T txn, KeySetId k, TransportId t,
long timePeriod, long base, byte[] bitmap) throws DbException;
/**
* Sets the versions of the sync protocol supported by the given contact.
*/
void setSyncVersions(T txn, ContactId c, List<Byte> supported)
throws DbException;
/**
* Marks the given transport keys as usable for outgoing streams.
*/
......
......@@ -65,6 +65,7 @@ import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.sync.event.SyncVersionsUpdatedEvent;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeySet;
......@@ -716,6 +717,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.getSettings(txn, namespace);
}
@Override
public List<Byte> getSyncVersions(Transaction transaction, ContactId c)
throws DbException {
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
return db.getSyncVersions(txn, c);
}
@Override
public Collection<TransportKeySet> getTransportKeys(Transaction transaction,
TransportId t) throws DbException {
......@@ -1046,6 +1056,17 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
db.setReorderingWindow(txn, k, t, timePeriod, base, bitmap);
}
@Override
public void setSyncVersions(Transaction transaction, ContactId c,
List<Byte> supported) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
db.setSyncVersions(txn, c, supported);
transaction.attach(new SyncVersionsUpdatedEvent(c, supported));
}
@Override
public void setTransportKeysActive(Transaction transaction, TransportId t,
KeySetId k) throws DbException {
......
......@@ -98,7 +98,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing
static final int CODE_SCHEMA_VERSION = 46;
static final int CODE_SCHEMA_VERSION = 47;
// Time period offsets for incoming transport keys
private static final int OFFSET_PREV = -1;
......@@ -135,6 +135,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " handshakePublicKey _BINARY," // Null if key is unknown
+ " localAuthorId _HASH NOT NULL,"
+ " verified BOOLEAN NOT NULL,"
+ " syncVersions _BINARY DEFAULT '00' NOT NULL,"
+ " PRIMARY KEY (contactId),"
+ " FOREIGN KEY (localAuthorId)"
+ " REFERENCES localAuthors (authorId)"
......@@ -461,7 +462,8 @@ abstract class JdbcDatabase implements Database<Connection> {
new Migration42_43(dbTypes),
new Migration43_44(dbTypes),
new Migration44_45(),
new Migration45_46()
new Migration45_46(),
new Migration46_47(dbTypes)
);
}
......@@ -2328,6 +2330,32 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public List<Byte> getSyncVersions(Connection txn, ContactId c)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT syncVersions FROM contacts"
+ " WHERE contactId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
byte[] bytes = rs.getBytes(1);
List<Byte> supported = new ArrayList<>(bytes.length);
for (byte b : bytes) supported.add(b);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
return supported;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public Collection<TransportKeySet> getTransportKeys(Connection txn,
TransportId t) throws DbException {
......@@ -3161,6 +3189,29 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public void setSyncVersions(Connection txn, ContactId c,
List<Byte> supported) throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE contacts SET syncVersions = ?"
+ " WHERE contactId = ?";
ps = txn.prepareStatement(sql);
byte[] bytes = new byte[supported.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = supported.get(i);
}
ps.setBytes(1, bytes);
ps.setInt(2, c.getInt());
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void setTransportKeysActive(Connection txn, TransportId t,
KeySetId k) throws DbException {
......
......@@ -31,8 +31,7 @@ class Migration45_46 implements Migration<Connection> {
try {
s = txn.createStatement();
s.execute("ALTER TABLE messages"
+ " ADD COLUMN temporary BOOLEAN NOT NULL"
+ " DEFAULT (FALSE)");
+ " ADD COLUMN temporary BOOLEAN DEFAULT FALSE NOT NULL");
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);
......
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration46_47 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration46_47.class.getName());
private final DatabaseTypes dbTypes;
Migration46_47(DatabaseTypes dbTypes) {
this.dbTypes = dbTypes;
}
@Override
public int getStartVersion() {
return 46;
}
@Override
public int getEndVersion() {
return 47;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
s.execute(dbTypes.replaceTypes("ALTER TABLE contacts"
+ " ADD COLUMN syncVersions"
+ " _BINARY DEFAULT '00' NOT NULL"));
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
}
......@@ -17,6 +17,7 @@ import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.sync.SyncSession;
import org.briarproject.bramble.api.sync.Versions;
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
import org.briarproject.bramble.api.sync.event.MessageRequestedEvent;
import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
......@@ -39,9 +40,11 @@ import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
import static org.briarproject.bramble.api.sync.SyncConstants.SUPPORTED_VERSIONS;
import static org.briarproject.bramble.util.LogUtils.logException;
/**
......@@ -55,7 +58,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
class DuplexOutgoingSession implements SyncSession, EventListener {
private static final Logger LOG =
Logger.getLogger(DuplexOutgoingSession.class.getName());
getLogger(DuplexOutgoingSession.class.getName());
private static final ThrowingRunnable<IOException> CLOSE = () -> {
};
......@@ -103,6 +106,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
public void run() throws IOException {
eventBus.addListener(this);
try {
// Send our supported protocol versions
recordWriter.writeVersions(new Versions(SUPPORTED_VERSIONS));
// Start a query for each type of record
generateAck();
generateBatch();
......
......@@ -18,14 +18,17 @@ import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.SyncRecordReader;
import org.briarproject.bramble.api.sync.SyncSession;
import org.briarproject.bramble.api.sync.Versions;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
import static org.briarproject.bramble.util.LogUtils.logException;
......@@ -37,7 +40,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
class IncomingSession implements SyncSession, EventListener {
private static final Logger LOG =
Logger.getLogger(IncomingSession.class.getName());
getLogger(IncomingSession.class.getName());
private final DatabaseComponent db;
private final Executor dbExecutor;
......@@ -80,6 +83,9 @@ class IncomingSession implements SyncSession, EventListener {
} else if (recordReader.hasRequest()) {
Request r = recordReader.readRequest();
dbExecutor.execute(new ReceiveRequest(r));
} else if (recordReader.hasVersions()) {
Versions v = recordReader.readVersions();
dbExecutor.execute(new ReceiveVersions(v));
} else {
// unknown records are ignored in RecordReader#eof()
throw new FormatException();
......@@ -190,4 +196,26 @@ class IncomingSession implements SyncSession, EventListener {
}
}
}
private class ReceiveVersions implements Runnable {
private final Versions versions;
private ReceiveVersions(Versions versions) {
this.versions = versions;
}
@DatabaseExecutor
@Override
public void run() {
try {
List<Byte> supported = versions.getSupportedVersions();
db.transaction(false,
txn -> db.setSyncVersions(txn, contactId, supported));
} catch (DbException e) {
logException(LOG, WARNING, e);
interrupt();
}
}
}
}
......@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.sync.SyncSession;
import org.briarproject.bramble.api.sync.Versions;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.IOException;
......@@ -29,9 +30,11 @@ import javax.annotation.concurrent.ThreadSafe;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
import static org.briarproject.bramble.api.sync.SyncConstants.SUPPORTED_VERSIONS;
import static org.briarproject.bramble.util.LogUtils.logException;
/**
......@@ -44,7 +47,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
class SimplexOutgoingSession implements SyncSession, EventListener {
private static final Logger LOG =
Logger.getLogger(SimplexOutgoingSession.class.getName());
getLogger(SimplexOutgoingSession.class.getName());
private static final ThrowingRunnable<IOException> CLOSE = () -> {
};
......@@ -80,6 +83,8 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
public void run() throws IOException {
eventBus.addListener(this);
try {
// Send our supported protocol versions
recordWriter.writeVersions(new Versions(SUPPORTED_VERSIONS));
// Start a query for each type of record
dbExecutor.execute(new GenerateAck());
dbExecutor.execute(new GenerateBatch());
......
......@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.SyncRecordReader;
import org.briarproject.bramble.api.sync.Versions;
import org.briarproject.bramble.util.ByteUtils;
import java.io.IOException;
......@@ -26,6 +27,8 @@ import static org.briarproject.bramble.api.sync.RecordTypes.ACK;
import static org.briarproject.bramble.api.sync.RecordTypes.MESSAGE;
import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
......@@ -45,7 +48,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
private static boolean isKnownRecordType(byte type) {
return type == ACK || type == MESSAGE || type == OFFER ||