diff --git a/briar-api/src/org/briarproject/api/DeviceId.java b/briar-api/src/org/briarproject/api/DeviceId.java new file mode 100644 index 0000000000000000000000000000000000000000..2b72d681dea60d9c234e954609537f7516494ad4 --- /dev/null +++ b/briar-api/src/org/briarproject/api/DeviceId.java @@ -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); + } +} diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java index dd165c481223218ce5cea273a3a3efb372babd89..852affa2db17b4edef84ff581f5bd8fdedefd0a7 100644 --- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java +++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java @@ -1,5 +1,6 @@ package org.briarproject.api.db; +import org.briarproject.api.DeviceId; import org.briarproject.api.TransportId; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; @@ -137,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; diff --git a/briar-core/src/org/briarproject/db/Database.java b/briar-core/src/org/briarproject/db/Database.java index 9236c6e296142f7f2a306b594e217146a434aeb8..e912671b536bdef0b3a7f2d73a405e9aa8ca06db 100644 --- a/briar-core/src/org/briarproject/db/Database.java +++ b/briar-core/src/org/briarproject/db/Database.java @@ -1,5 +1,6 @@ package org.briarproject.db; +import org.briarproject.api.DeviceId; import org.briarproject.api.TransportId; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; @@ -256,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 diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java index ccfa60eccf441d6c939b1bdd1afa383be444b336..39c0f796f0faa10cc226c7b317353009a95dc7b0 100644 --- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java +++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java @@ -1,5 +1,6 @@ package org.briarproject.db; +import org.briarproject.api.DeviceId; import org.briarproject.api.TransportId; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; @@ -542,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 { diff --git a/briar-core/src/org/briarproject/db/JdbcDatabase.java b/briar-core/src/org/briarproject/db/JdbcDatabase.java index 63b6aa18618012da2d65e444e9cdaed0a642e601..411d7246c7dbafea7d075579281e4bc002f32db0 100644 --- a/briar-core/src/org/briarproject/db/JdbcDatabase.java +++ b/briar-core/src/org/briarproject/db/JdbcDatabase.java @@ -1,5 +1,6 @@ package org.briarproject.db; +import org.briarproject.api.DeviceId; import org.briarproject.api.TransportId; import org.briarproject.api.UniqueId; import org.briarproject.api.contact.Contact; @@ -484,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; diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java index 2d4fc5bcc1779e3758150fe73745a5f9cf70a1a3..5da83e49ddaaef91fb4bd5210adb031bd8a0eea5 100644 --- a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java +++ b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java @@ -2,6 +2,7 @@ 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; @@ -43,6 +44,7 @@ import java.util.Map.Entry; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Logger; +import static java.util.logging.Level.INFO; 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; @@ -100,9 +102,10 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, 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(), e.getKey(), e.getValue(), 0); + 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) { @@ -141,9 +144,10 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, return out.toByteArray(); } - private void storeMessage(GroupId g, TransportId t, TransportProperties p, - long version) throws DbException, IOException { - byte[] body = encodeProperties(t, p, version); + 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(); @@ -153,13 +157,13 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, db.addLocalMessage(m, CLIENT_ID, metadataEncoder.encode(d)); } - private byte[] encodeProperties(TransportId t, TransportProperties p, - long version) { + private byte[] encodeProperties(DeviceId dev, TransportId t, + TransportProperties p, long version) { ByteArrayOutputStream out = new ByteArrayOutputStream(); BdfWriter w = bdfWriterFactory.createWriter(out); try { - // TODO: Device ID w.writeListStart(); + w.writeRaw(dev.getBytes()); w.writeString(t.getString()); w.writeInteger(version); w.writeDictionary(p); @@ -232,8 +236,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, ByteArrayInputStream in = new ByteArrayInputStream(raw, MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH); BdfReader r = bdfReaderFactory.createReader(in); - // TODO: Device ID r.readListStart(); + r.skipRaw(); // Device ID r.skipString(); // Transport ID r.skipInteger(); // Version r.readDictionaryStart(); @@ -242,9 +246,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, String value = r.readString(MAX_PROPERTY_LENGTH); p.put(key, value); } - r.readDictionaryEnd(); - r.readListEnd(); - if (!r.eof()) throw new FormatException(); return p; } @@ -310,14 +311,19 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, p = old; } // Store the merged properties in the local group + DeviceId dev = db.getDeviceId(); long version = latest == null ? 0 : latest.version + 1; - storeMessage(localGroup.getId(), t, p, version); + storeMessage(localGroup.getId(), dev, t, p, version); + if (LOG.isLoggable(INFO)) { + LOG.info("Stored local properties for " + t.getString() + + ", version " + 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(), t, p, version); + storeMessage(g.getId(), dev, t, p, version); } } catch (IOException e) { throw new DbException(e); diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java b/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java index 0a140dd5bacc5734c4e57f2e7f8b5b5b005df57a..eeee9f333447c2489c62e27d42da582eca6bde9c 100644 --- a/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java +++ b/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java @@ -1,6 +1,7 @@ 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; @@ -53,10 +54,11 @@ class TransportPropertyValidator implements MessageValidator { ByteArrayInputStream in = new ByteArrayInputStream(raw, MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH); BdfReader r = bdfReaderFactory.createReader(in); - // TODO: Device ID r.readListStart(); - String id = r.readString(MAX_TRANSPORT_ID_LENGTH); - if (id.length() == 0) throw new FormatException(); + 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(); @@ -71,7 +73,7 @@ class TransportPropertyValidator implements MessageValidator { if (!r.eof()) throw new FormatException(); // Return the metadata BdfDictionary d = new BdfDictionary(); - d.put("transportId", id); + d.put("transportId", transportId); d.put("version", version); d.put("local", false); return metadataEncoder.encode(d); diff --git a/briar-core/src/org/briarproject/util/StringUtils.java b/briar-core/src/org/briarproject/util/StringUtils.java index 822831ac05b347daa88b041144a6bf100a93cd04..0753748e88c7c63ac8220d82c4041ee8094266a8 100644 --- a/briar-core/src/org/briarproject/util/StringUtils.java +++ b/briar-core/src/org/briarproject/util/StringUtils.java @@ -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));