mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 05:09:53 +01:00
Merge branch '346-smaller-qr-codes' into 'master'
Encode transport properties more compactly in QR codes The [original BQP spec](https://code.briarproject.org/akwizgran/briar/wikis/BQP) described a compact encoding for transport properties, with the goal of making the QR code as small as possible. At some point during the implementation, I asked @str4d to use TransportIds and TransportProperties instead, as described in the [current spec](https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BQP.md). That was a mistake. Using the original format reduces the payload from 60 to 34 bytes (43% smaller) for Bluetooth only, and from 96 to 49 bytes (49% smaller) for Bluetooth and LAN. This makes it easier to scan codes from low-resolution screens using fixed-focus and/or low-resolution cameras. Using this branch I can exchange codes between the Sony Xperia Tipo (320x480 screen, fixed focus, 640x480 preview size) and the Huawei Ascend Y300 (480x800 screen, infinity focus, 1280x720 preview size). This also removes an obstacle to implementing #558, as TransportIds are no longer included in QR codes. Closes #346. See merge request !394
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
package org.briarproject.keyagreement;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.KeyPair;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.Payload;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
import org.briarproject.api.plugins.PluginManager;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
@@ -14,7 +16,10 @@ import org.briarproject.api.system.Clock;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -68,14 +73,13 @@ class KeyAgreementConnector {
|
||||
byte[] commitment = crypto.deriveKeyCommitment(
|
||||
localKeyPair.getPublic().getEncoded());
|
||||
// Start all listeners and collect their descriptors
|
||||
List<TransportDescriptor> descriptors =
|
||||
new ArrayList<TransportDescriptor>();
|
||||
Map<TransportId, BdfList> descriptors =
|
||||
new HashMap<TransportId, BdfList>();
|
||||
for (DuplexPlugin plugin : pluginManager.getKeyAgreementPlugins()) {
|
||||
KeyAgreementListener l = plugin.createKeyAgreementListener(
|
||||
commitment);
|
||||
KeyAgreementListener l =
|
||||
plugin.createKeyAgreementListener(commitment);
|
||||
if (l != null) {
|
||||
TransportDescriptor d = l.getDescriptor();
|
||||
descriptors.add(d);
|
||||
descriptors.put(plugin.getId(), l.getDescriptor());
|
||||
pending.add(connect.submit(new ReadableTask(l.listen())));
|
||||
listeners.add(l);
|
||||
}
|
||||
@@ -100,13 +104,16 @@ class KeyAgreementConnector {
|
||||
|
||||
// Start connecting over supported transports
|
||||
LOG.info("Starting outgoing BQP connections");
|
||||
for (TransportDescriptor d : remotePayload.getTransportDescriptors()) {
|
||||
DuplexPlugin plugin = (DuplexPlugin) pluginManager.getPlugin(
|
||||
d.getIdentifier());
|
||||
if (plugin != null)
|
||||
Map<TransportId, BdfList> descriptors =
|
||||
remotePayload.getTransportDescriptors();
|
||||
for (Entry<TransportId, BdfList> e : descriptors.entrySet()) {
|
||||
Plugin p = pluginManager.getPlugin(e.getKey());
|
||||
if (p instanceof DuplexPlugin) {
|
||||
DuplexPlugin plugin = (DuplexPlugin) p;
|
||||
pending.add(connect.submit(new ReadableTask(
|
||||
new ConnectorTask(plugin, remotePayload.getCommitment(),
|
||||
d, end))));
|
||||
e.getValue(), end))));
|
||||
}
|
||||
}
|
||||
|
||||
// Get chosen connection
|
||||
@@ -170,12 +177,12 @@ class KeyAgreementConnector {
|
||||
private class ConnectorTask implements Callable<KeyAgreementConnection> {
|
||||
|
||||
private final byte[] commitment;
|
||||
private final TransportDescriptor descriptor;
|
||||
private final BdfList descriptor;
|
||||
private final long end;
|
||||
private final DuplexPlugin plugin;
|
||||
|
||||
private ConnectorTask(DuplexPlugin plugin, byte[] commitment,
|
||||
TransportDescriptor descriptor, long end) {
|
||||
BdfList descriptor, long end) {
|
||||
this.plugin = plugin;
|
||||
this.commitment = commitment;
|
||||
this.descriptor = descriptor;
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
package org.briarproject.keyagreement;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.data.BdfWriter;
|
||||
import org.briarproject.api.data.BdfWriterFactory;
|
||||
import org.briarproject.api.keyagreement.Payload;
|
||||
import org.briarproject.api.keyagreement.PayloadEncoder;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class PayloadEncoderImpl implements PayloadEncoder {
|
||||
|
||||
private final BdfWriterFactory bdfWriterFactory;
|
||||
|
||||
@Inject
|
||||
public PayloadEncoderImpl(BdfWriterFactory bdfWriterFactory) {
|
||||
PayloadEncoderImpl(BdfWriterFactory bdfWriterFactory) {
|
||||
this.bdfWriterFactory = bdfWriterFactory;
|
||||
}
|
||||
|
||||
@@ -30,18 +36,13 @@ class PayloadEncoderImpl implements PayloadEncoder {
|
||||
w.writeListStart(); // Payload start
|
||||
w.writeLong(PROTOCOL_VERSION);
|
||||
w.writeRaw(p.getCommitment());
|
||||
w.writeListStart(); // Descriptors start
|
||||
for (TransportDescriptor d : p.getTransportDescriptors()) {
|
||||
w.writeListStart();
|
||||
w.writeString(d.getIdentifier().getString());
|
||||
w.writeDictionary(d.getProperties());
|
||||
w.writeListEnd();
|
||||
}
|
||||
w.writeListEnd(); // Descriptors end
|
||||
Map<TransportId, BdfList> descriptors = p.getTransportDescriptors();
|
||||
for (BdfList descriptor : descriptors.values())
|
||||
w.writeList(descriptor);
|
||||
w.writeListEnd(); // Payload end
|
||||
} catch (IOException e) {
|
||||
// Shouldn't happen with ByteArrayOutputStream
|
||||
throw new RuntimeException(e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
@@ -2,30 +2,34 @@ package org.briarproject.keyagreement;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.data.BdfReader;
|
||||
import org.briarproject.api.data.BdfReaderFactory;
|
||||
import org.briarproject.api.keyagreement.Payload;
|
||||
import org.briarproject.api.keyagreement.PayloadParser;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||
import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class PayloadParserImpl implements PayloadParser {
|
||||
|
||||
private final BdfReaderFactory bdfReaderFactory;
|
||||
|
||||
@Inject
|
||||
public PayloadParserImpl(BdfReaderFactory bdfReaderFactory) {
|
||||
PayloadParserImpl(BdfReaderFactory bdfReaderFactory) {
|
||||
this.bdfReaderFactory = bdfReaderFactory;
|
||||
}
|
||||
|
||||
@@ -33,36 +37,28 @@ class PayloadParserImpl implements PayloadParser {
|
||||
public Payload parse(byte[] raw) throws IOException {
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(raw);
|
||||
BdfReader r = bdfReaderFactory.createReader(in);
|
||||
r.readListStart(); // Payload start
|
||||
int proto = (int) r.readLong();
|
||||
if (proto != PROTOCOL_VERSION)
|
||||
throw new FormatException();
|
||||
byte[] commitment = r.readRaw(COMMIT_LENGTH);
|
||||
if (commitment.length != COMMIT_LENGTH)
|
||||
throw new FormatException();
|
||||
List<TransportDescriptor> descriptors = new ArrayList<TransportDescriptor>();
|
||||
r.readListStart(); // Descriptors start
|
||||
while (r.hasList()) {
|
||||
r.readListStart();
|
||||
while (!r.hasListEnd()) {
|
||||
TransportId id =
|
||||
new TransportId(r.readString(MAX_PROPERTY_LENGTH));
|
||||
TransportProperties p = new TransportProperties();
|
||||
r.readDictionaryStart();
|
||||
while (!r.hasDictionaryEnd()) {
|
||||
String key = r.readString(MAX_PROPERTY_LENGTH);
|
||||
String value = r.readString(MAX_PROPERTY_LENGTH);
|
||||
p.put(key, value);
|
||||
}
|
||||
r.readDictionaryEnd();
|
||||
descriptors.add(new TransportDescriptor(id, p));
|
||||
// The payload is a BDF list with two or more elements
|
||||
BdfList payload = r.readList();
|
||||
if (payload.size() < 2) throw new FormatException();
|
||||
if (!r.eof()) throw new FormatException();
|
||||
// First element: the protocol version
|
||||
long protocolVersion = payload.getLong(0);
|
||||
if (protocolVersion != PROTOCOL_VERSION) throw new FormatException();
|
||||
// Second element: the public key commitment
|
||||
byte[] commitment = payload.getRaw(1);
|
||||
if (commitment.length != COMMIT_LENGTH) throw new FormatException();
|
||||
// Remaining elements: transport descriptors
|
||||
Map<TransportId, BdfList> recognised =
|
||||
new HashMap<TransportId, BdfList>();
|
||||
for (int i = 2; i < payload.size(); i++) {
|
||||
BdfList descriptor = payload.getList(i);
|
||||
long transportId = descriptor.getLong(0);
|
||||
if (transportId == TRANSPORT_ID_BLUETOOTH) {
|
||||
recognised.put(new TransportId("bt"), descriptor);
|
||||
} else if (transportId == TRANSPORT_ID_LAN) {
|
||||
recognised.put(new TransportId("lan"), descriptor);
|
||||
}
|
||||
r.readListEnd();
|
||||
}
|
||||
r.readListEnd(); // Descriptors end
|
||||
r.readListEnd(); // Payload end
|
||||
if (!r.eof())
|
||||
throw new FormatException();
|
||||
return new Payload(commitment, descriptors);
|
||||
return new Payload(commitment, recognised);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.briarproject.api.event.TransportEnabledEvent;
|
||||
import org.briarproject.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.api.lifecycle.Service;
|
||||
import org.briarproject.api.lifecycle.ServiceException;
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.api.plugins.ConnectionManager;
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
import org.briarproject.api.plugins.PluginCallback;
|
||||
@@ -42,11 +43,14 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class PluginManagerImpl implements PluginManager, Service {
|
||||
|
||||
private static final Logger LOG =
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.plugins.file;
|
||||
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.api.plugins.TransportConnectionReader;
|
||||
import org.briarproject.api.plugins.TransportConnectionWriter;
|
||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||
@@ -17,10 +18,13 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.api.transport.TransportConstants.MIN_STREAM_LENGTH;
|
||||
|
||||
public abstract class FilePlugin implements SimplexPlugin {
|
||||
@NotNullByDefault
|
||||
abstract class FilePlugin implements SimplexPlugin {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(FilePlugin.class.getName());
|
||||
@@ -32,6 +36,7 @@ public abstract class FilePlugin implements SimplexPlugin {
|
||||
|
||||
protected volatile boolean running = false;
|
||||
|
||||
@Nullable
|
||||
protected abstract File chooseOutputDirectory();
|
||||
protected abstract Collection<File> findFilesByName(String filename);
|
||||
protected abstract void writerFinished(File f);
|
||||
@@ -82,6 +87,7 @@ public abstract class FilePlugin implements SimplexPlugin {
|
||||
return filename.toLowerCase(Locale.US).matches("[a-z]{8}\\.dat");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TransportConnectionWriter createWriter(String filename) {
|
||||
if (!running) return null;
|
||||
File dir = chooseOutputDirectory();
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.briarproject.plugins.tcp;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.api.plugins.Backoff;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||
@@ -19,6 +21,7 @@ import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
@@ -29,8 +32,11 @@ import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
|
||||
import static org.briarproject.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
|
||||
|
||||
@NotNullByDefault
|
||||
class LanTcpPlugin extends TcpPlugin {
|
||||
|
||||
static final TransportId ID = new TransportId("lan");
|
||||
@@ -40,7 +46,6 @@ class LanTcpPlugin extends TcpPlugin {
|
||||
|
||||
private static final int MAX_ADDRESSES = 5;
|
||||
private static final String PROP_IP_PORTS = "ipPorts";
|
||||
private static final String PROP_IP_PORT = "ipPort";
|
||||
private static final String SEPARATOR = ",";
|
||||
|
||||
LanTcpPlugin(Executor ioExecutor, Backoff backoff,
|
||||
@@ -186,23 +191,26 @@ class LanTcpPlugin extends TcpPlugin {
|
||||
LOG.info("Could not bind server socket for key agreement");
|
||||
return null;
|
||||
}
|
||||
TransportProperties p = new TransportProperties();
|
||||
SocketAddress local = ss.getLocalSocketAddress();
|
||||
p.put(PROP_IP_PORT, getIpPortString((InetSocketAddress) local));
|
||||
TransportDescriptor d = new TransportDescriptor(ID, p);
|
||||
return new LanKeyAgreementListener(d, ss);
|
||||
BdfList descriptor = new BdfList();
|
||||
descriptor.add(TRANSPORT_ID_LAN);
|
||||
InetSocketAddress local =
|
||||
(InetSocketAddress) ss.getLocalSocketAddress();
|
||||
descriptor.add(local.getAddress().getAddress());
|
||||
descriptor.add(local.getPort());
|
||||
return new LanKeyAgreementListener(descriptor, ss);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||
byte[] commitment, BdfList descriptor, long timeout) {
|
||||
if (!isRunning()) return null;
|
||||
if (!ID.equals(d.getIdentifier())) return null;
|
||||
TransportProperties p = d.getProperties();
|
||||
if (p == null) return null;
|
||||
String ipPort = p.get(PROP_IP_PORT);
|
||||
InetSocketAddress remote = parseSocketAddress(ipPort);
|
||||
if (remote == null) return null;
|
||||
InetSocketAddress remote;
|
||||
try {
|
||||
remote = parseSocketAddress(descriptor);
|
||||
} catch (FormatException e) {
|
||||
LOG.info("Invalid IP/port in key agreement descriptor");
|
||||
return null;
|
||||
}
|
||||
if (!isConnectable(remote)) {
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
SocketAddress local = socket.getLocalSocketAddress();
|
||||
@@ -228,11 +236,25 @@ class LanTcpPlugin extends TcpPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
private InetSocketAddress parseSocketAddress(BdfList descriptor)
|
||||
throws FormatException {
|
||||
byte[] address = descriptor.getRaw(1);
|
||||
int port = descriptor.getLong(2).intValue();
|
||||
if (port < 1 || port > MAX_16_BIT_UNSIGNED) throw new FormatException();
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByAddress(address);
|
||||
return new InetSocketAddress(addr, port);
|
||||
} catch (UnknownHostException e) {
|
||||
// Invalid address length
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
|
||||
private class LanKeyAgreementListener extends KeyAgreementListener {
|
||||
|
||||
private final ServerSocket ss;
|
||||
|
||||
public LanKeyAgreementListener(TransportDescriptor descriptor,
|
||||
private LanKeyAgreementListener(BdfList descriptor,
|
||||
ServerSocket ss) {
|
||||
super(descriptor);
|
||||
this.ss = ss;
|
||||
|
||||
@@ -2,8 +2,10 @@ package org.briarproject.plugins.tcp;
|
||||
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.PseudoRandom;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.keyagreement.KeyAgreementListener;
|
||||
import org.briarproject.api.keyagreement.TransportDescriptor;
|
||||
import org.briarproject.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.api.plugins.Backoff;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
@@ -28,10 +30,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
abstract class TcpPlugin implements DuplexPlugin {
|
||||
|
||||
private static final Pattern DOTTED_QUAD =
|
||||
@@ -141,7 +147,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
||||
});
|
||||
}
|
||||
|
||||
protected void tryToClose(ServerSocket ss) {
|
||||
protected void tryToClose(@Nullable ServerSocket ss) {
|
||||
try {
|
||||
if (ss != null) ss.close();
|
||||
} catch (IOException e) {
|
||||
@@ -252,6 +258,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected InetSocketAddress parseSocketAddress(String ipPort) {
|
||||
if (StringUtils.isNullOrEmpty(ipPort)) return null;
|
||||
String[] split = ipPort.split(":");
|
||||
@@ -298,7 +305,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
||||
|
||||
@Override
|
||||
public DuplexTransportConnection createKeyAgreementConnection(
|
||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||
byte[] commitment, BdfList descriptor, long timeout) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package org.briarproject.plugins.tcp;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.api.plugins.Backoff;
|
||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||
import org.briarproject.api.properties.TransportProperties;
|
||||
@@ -14,6 +16,8 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
class WanTcpPlugin extends TcpPlugin {
|
||||
|
||||
static final TransportId ID = new TransportId("wan");
|
||||
|
||||
@@ -1,24 +1,34 @@
|
||||
package org.briarproject.util;
|
||||
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.util.Collection;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.nio.charset.CodingErrorAction.IGNORE;
|
||||
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||
|
||||
@NotNullByDefault
|
||||
public class StringUtils {
|
||||
|
||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
private static Pattern MAC = Pattern.compile("[0-9a-f]{2}:[0-9a-f]{2}:" +
|
||||
"[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}",
|
||||
CASE_INSENSITIVE);
|
||||
|
||||
private static final char[] HEX = new char[] {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
public static boolean isNullOrEmpty(String s) {
|
||||
public static boolean isNullOrEmpty(@Nullable String s) {
|
||||
return s == null || s.length() == 0;
|
||||
}
|
||||
|
||||
@@ -61,7 +71,9 @@ public class StringUtils {
|
||||
return fromUtf8(utf8, 0, maxUtf8Length);
|
||||
}
|
||||
|
||||
/** Converts the given byte array to a hex character array. */
|
||||
/**
|
||||
* Converts the given byte array to a hex character array.
|
||||
*/
|
||||
private static char[] toHexChars(byte[] bytes) {
|
||||
char[] hex = new char[bytes.length * 2];
|
||||
for (int i = 0, j = 0; i < bytes.length; i++) {
|
||||
@@ -71,12 +83,16 @@ public class StringUtils {
|
||||
return hex;
|
||||
}
|
||||
|
||||
/** Converts the given byte array to a hex string. */
|
||||
/**
|
||||
* Converts the given byte array to a hex string.
|
||||
*/
|
||||
public static String toHexString(byte[] bytes) {
|
||||
return new String(toHexChars(bytes));
|
||||
}
|
||||
|
||||
/** Converts the given hex string to a byte array. */
|
||||
/**
|
||||
* Converts the given hex string to a byte array.
|
||||
*/
|
||||
public static byte[] fromHexString(String hex) {
|
||||
int len = hex.length();
|
||||
if (len % 2 != 0)
|
||||
@@ -107,4 +123,20 @@ public class StringUtils {
|
||||
public static boolean utf8IsTooLong(String s, int maxLength) {
|
||||
return toUtf8(s).length > maxLength;
|
||||
}
|
||||
|
||||
public static byte[] macToBytes(String mac) {
|
||||
if (!MAC.matcher(mac).matches()) throw new IllegalArgumentException();
|
||||
return fromHexString(mac.replaceAll(":", ""));
|
||||
}
|
||||
|
||||
public static String macToString(byte[] mac) {
|
||||
if (mac.length != 6) throw new IllegalArgumentException();
|
||||
StringBuilder s = new StringBuilder();
|
||||
for (byte b : mac) {
|
||||
if (s.length() > 0) s.append(':');
|
||||
s.append(HEX[(b >> 4) & 0xF]);
|
||||
s.append(HEX[b & 0xF]);
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user