diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/Pair.java b/bramble-api/src/main/java/org/briarproject/bramble/api/Pair.java index cd81f1adce28cbf5f908b9bb649d61775a8271ff..10d53d267e6ca87f46c5a93012919d7186e7c2f0 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/Pair.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/Pair.java @@ -23,4 +23,8 @@ public class Pair<A, B> { public B getSecond() { return second; } + + public String toString() { + return "<"+first.toString()+", "+second.toString()+">"; + } } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/LoRaConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/LoRaConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..57955c17095afd515a97f9623f914677829263d8 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/LoRaConstants.java @@ -0,0 +1,19 @@ +package org.briarproject.bramble.api.plugin; + +import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; + +public interface LoRaConstants { + TransportId ID = new TransportId("org.briarproject.bramble.lora"); + + int PKG_SIZE = 255; + int PAYLOAD_SIZE = PKG_SIZE-TAG_LENGTH; //239 + + int MAX_LATENCY = 5*60*60*1000; //5 Hours - since a big Message can fill up the Tx-Queue quite fast + int MAX_IDLE_TIME = Integer.MAX_VALUE; + + //TODO: Do we use Backoff? + int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute + int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins + double BACKOFF_BASE = 1.2; + +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java index 0856b877394e636b0a73af9da7580fe95d221fca..cf6f9944ffcbc8b3b2433128e7203c0b5a447f8c 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/OutgoingKeys.java @@ -17,6 +17,10 @@ public class OutgoingKeys { private final long timePeriod, streamCounter; private final boolean active; + public String toString() { + return "timeperiod "+timePeriod+" streamCounter "+streamCounter+" active:"+active+" (keys omnitted)"; + } + public OutgoingKeys(SecretKey tagKey, SecretKey headerKey, long timePeriod, boolean active) { this(tagKey, headerKey, timePeriod, 0, active); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StreamContext.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StreamContext.java index 7ef48102399074cce5131b942dea024f9a42c76f..78d2f3f8ef4f4184cfcdd32f5778b0c10ac084cd 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StreamContext.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/StreamContext.java @@ -6,6 +6,9 @@ import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.nullsafety.NotNullByDefault; +import java.util.logging.Logger; +import org.briarproject.bramble.util.ByteUtils; + import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -15,6 +18,9 @@ import static org.briarproject.nullsafety.NullSafety.requireExactlyOneNull; @NotNullByDefault public class StreamContext { + private static final Logger LOG = + Logger.getLogger(StreamContext.class.getName()); + @Nullable private final ContactId contactId; @Nullable @@ -24,6 +30,13 @@ public class StreamContext { private final long streamNumber; private final boolean handshakeMode; + public String toString() { + if(contactId != null) + return "contactId "+contactId.getInt()/*+" transportId "+transportId*/+" tagKey "+ByteUtils.bytesToHex(tagKey.getBytes())+" headerKey "+ByteUtils.bytesToHex(headerKey.getBytes())+" streamNr "+streamNumber+" handshakeMode "+handshakeMode; + else + return "contactid=null"; + } + public StreamContext(@Nullable ContactId contactId, @Nullable PendingContactId pendingContactId, TransportId transportId, SecretKey tagKey, SecretKey headerKey, @@ -36,6 +49,8 @@ public class StreamContext { this.headerKey = headerKey; this.streamNumber = streamNumber; this.handshakeMode = handshakeMode; + + LOG.info("new StreamCtx("+this); } @Nullable diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java index 81bef3a3915205083999a850bc00e7ef0eb7aed9..6bb14b78062e27df8ce605e210aa28ea70039c3b 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeySet.java @@ -61,4 +61,10 @@ public class TransportKeySet { return o instanceof TransportKeySet && keySetId.equals(((TransportKeySet) o).keySetId); } + + public String toString() { + if(contactId == null) + return "Keys for PendingContact: "+keys; + return "Keys contact"+contactId.getInt()+": "+keys; + } } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java index 60c98b174ff825e452df90ec85da4a08df7ba7a3..568534f1de4a39108a56c29aff348707231b2f70 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/transport/TransportKeys.java @@ -22,6 +22,10 @@ public class TransportKeys { private final SecretKey rootKey; private final boolean alice; + public String toString() { + return "transport "+transportId+", a lot omnitted, currOutGoingKey: "+outCurr; + } + /** * Constructor for rotation mode. */ diff --git a/bramble-api/src/main/java/org/briarproject/bramble/util/ByteUtils.java b/bramble-api/src/main/java/org/briarproject/bramble/util/ByteUtils.java index 61b2378292e8389465e970fc2aa662642ad2412a..f91fd768a183cfa0c541d604796713b590f97cb2 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/util/ByteUtils.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/util/ByteUtils.java @@ -1,4 +1,5 @@ package org.briarproject.bramble.util; +import java.lang.System; public class ByteUtils { @@ -93,4 +94,27 @@ public class ByteUtils { if (dest >= 1 << bits) throw new AssertionError(); return dest; } + + public static byte[] concat(byte a1[], byte a2[]) { + if(a1 == null) + return a2; + if(a2 == null) + return a1; + + byte ret[] = new byte[a1.length+a2.length]; + System.arraycopy(a1, 0, ret, 0, a1.length); + System.arraycopy(a2, 0, ret, a1.length, a2.length); + return ret; + } + + public static String bytesToHex(byte in[]) { + final char hexDigit[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + char outArr[] = new char[in.length*2]; + for(int i=0; i<in.length; i++) { + outArr[i*2] = hexDigit[(in[i]>>>4)&0xF]; + outArr[i*2+1] = hexDigit[in[i]&0xF]; + } + return new String(outArr); + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/connection/IncomingSimplexSyncConnection.java b/bramble-core/src/main/java/org/briarproject/bramble/connection/IncomingSimplexSyncConnection.java index 705661d6ae84cdc6fc6d50361a4a1b89e85b7819..fa93ef672aba4e404376e153092270eba592d142 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/connection/IncomingSimplexSyncConnection.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/connection/IncomingSimplexSyncConnection.java @@ -14,6 +14,7 @@ import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.StreamReaderFactory; import org.briarproject.bramble.api.transport.StreamWriterFactory; import org.briarproject.nullsafety.NotNullByDefault; +import org.briarproject.bramble.util.ByteUtils; import java.io.IOException; @@ -54,6 +55,7 @@ class IncomingSimplexSyncConnection extends SyncConnection implements Runnable { StreamContext ctx; try { tag = readTag(reader.getInputStream()); + LOG.info("try to recognize tag "+ByteUtils.bytesToHex(tag)); // If we have a tag controller, defer marking the tag as recognised if (tagController == null) { ctx = keyManager.getStreamContext(transportId, tag); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterImpl.java index 55224c729858993c8e954e10569ba1f3c6c03e7c..82b3905e5fc2a27a80964666eb4ff3d68384a990 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/StreamEncrypterImpl.java @@ -7,6 +7,7 @@ import org.briarproject.nullsafety.NotNullByDefault; import java.io.IOException; import java.io.OutputStream; +import java.util.Arrays; import java.security.GeneralSecurityException; import javax.annotation.Nullable; @@ -24,10 +25,13 @@ import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_H import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH; import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; +import java.util.logging.Logger; @NotThreadSafe @NotNullByDefault class StreamEncrypterImpl implements StreamEncrypter { + private static final Logger LOG = + Logger.getLogger(StreamEncrypterImpl.class.getName()); private final OutputStream out; private final AuthenticatedCipher cipher; @@ -74,6 +78,8 @@ class StreamEncrypterImpl implements StreamEncrypter { if (writeTag) writeTag(); // Write the stream header if required if (writeStreamHeader) writeStreamHeader(); + + LOG.info("Payload:"+ByteUtils.bytesToHex(Arrays.copyOfRange(payload,0,payloadLength))+"; Final:"+finalFrame); // Encode the frame header FrameEncoder.encodeHeader(frameHeader, finalFrame, payloadLength, paddingLength); @@ -110,6 +116,7 @@ class StreamEncrypterImpl implements StreamEncrypter { } private void writeTag() throws IOException { + LOG.info("write Tag"); if (tag == null) throw new IllegalStateException(); out.write(tag, 0, tag.length); writeTag = false; @@ -123,6 +130,7 @@ class StreamEncrypterImpl implements StreamEncrypter { INT_16_BYTES); System.arraycopy(frameKey.getBytes(), 0, streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES, SecretKey.LENGTH); + LOG.info("write Header (Protocol:"+PROTOCOL_VERSION+", streamNumber:"+streamNumber+"), ..."); byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH]; System.arraycopy(streamHeaderNonce, 0, streamHeaderCiphertext, 0, STREAM_HEADER_NONCE_LENGTH); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/AbstractLoRaPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/AbstractLoRaPlugin.java new file mode 100644 index 0000000000000000000000000000000000000000..7bd852d6a07ad78d34a69f97ecd73dd91e0556c6 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/AbstractLoRaPlugin.java @@ -0,0 +1,174 @@ +package org.briarproject.bramble.plugin.lora; + +import org.briarproject.bramble.plugin.lora.DeviceManager; +import org.briarproject.bramble.plugin.lora.L2PWriter; +import org.briarproject.bramble.plugin.lora.L2PReader; +import org.briarproject.bramble.plugin.lora.L2PReaderFactory; +import org.briarproject.bramble.api.Pair; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.ConnectionHandler; +import org.briarproject.bramble.api.plugin.PluginCallback; +import org.briarproject.bramble.api.plugin.Backoff; +import org.briarproject.bramble.api.plugin.TransportConnectionReader; +import org.briarproject.bramble.api.plugin.TransportConnectionWriter; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.plugin.PluginException; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import java.util.concurrent.Executor; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collection; +import java.util.logging.Logger; + +import javax.annotation.concurrent.Immutable; + +import static java.util.Collections.singletonMap; +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; +import static org.briarproject.bramble.api.plugin.LoRaConstants.ID; +import static org.briarproject.bramble.api.plugin.file.RemovableDriveConstants.PROP_SUPPORTED; //TODO +import static org.briarproject.bramble.util.LogUtils.logException; + +@Immutable +@NotNullByDefault +abstract class AbstractLoRaPlugin implements SimplexPlugin/*, EventHandler, EventListener*/ { + + private static final Logger LOG = + getLogger(AbstractLoRaPlugin.class.getName()); + + protected final Clock clock; + protected final Backoff backoff; //TODO: Is this needed? + protected final long maxLatency; + protected final PluginCallback callback; + protected final int maxIdleTime; + protected DeviceManager devicemanager; + protected final Executor ioExecutor, wakefulIoExecutor; + protected L2PReaderFactory rf; + + AbstractLoRaPlugin( + Executor ioExecutor, + Executor wakefulIoExecutor, Clock clock, Backoff backoff, PluginCallback callback, long maxLatency, int maxIdleTime) { + LOG.info("AbstractLoRaPlugin::Constructor"); + this.clock = clock; + this.callback = callback; + this.backoff = backoff; + this.ioExecutor = ioExecutor; + this.wakefulIoExecutor = wakefulIoExecutor; + this.maxLatency = maxLatency; + this.maxIdleTime = maxIdleTime; + + this.rf = new L2PReaderFactory(callback); + this.devicemanager = new DeviceManager(); + } + + public LoRaAdapter getAdapter() { + return devicemanager.getAdapter(); + } + + public boolean TXenabled() { + return true; + } + + @Override + public TransportId getId() { + return ID; + } + + @Override + public long getMaxLatency() { + return maxLatency; + } + + @Override + public int getMaxIdleTime() { + // Unused for simplex transports + throw new UnsupportedOperationException(); + } + + @Override + public boolean isLossyAndCheap() { + return false; + } + + @Override + public State getState() { + LOG.info("getState(): "+devicemanager.getState()); + return devicemanager.getState(); + } + + @Override + public void start() throws PluginException { + LOG.info("start()"); + devicemanager.getAdapter().start(); + callback.pluginStateChanged(getState()); + } + + @Override + public void stop() throws PluginException { + LOG.info("stop()"); + devicemanager.getAdapter().stop(); + } + + //TODO + @Override + public int getReasonsDisabled() { + return 0; + } + + @Override + public boolean shouldPoll() { + return true; + } + + @Override + public int getPollingInterval() { + LOG.info("getPollingInterval(): "+backoff.getPollingInterval()); + return backoff.getPollingInterval(); + } + + //TODO: Switch to Events + @Override + public void poll(Collection<Pair<TransportProperties, ConnectionHandler>> properties) { + //backoff.increment(); + LOG.info("poll()"); + if (getState() != ACTIVE || !TXenabled()) return; + backoff.increment(); + for (Pair<TransportProperties, ConnectionHandler> p : properties) { + wakefulIoExecutor.execute(() -> { + //TODO: Is there anything to send? + TransportConnectionWriter w = new L2PWriter(this); + if (w != null) { + backoff.reset(); + p.getSecond().handleWriter(w); + } + }); + } + } + + @Override + public TransportConnectionReader createReader(TransportProperties p) { + //TODO: Where is that called? + LOG.info("createReader()"); + //callback.handleConnection(conn); used + return null; + /*try { + return new TransportInputStreamReader(openInputStream(p)); + } catch (IOException e) { + logException(LOG, WARNING, e); + return null; + }*/ + } + + @Override + public TransportConnectionWriter createWriter(TransportProperties p) { + //TODO: Where is that called? + LOG.info("createWriter()"); + return new L2PWriter(this); + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/AbstractLoRaPluginFactory.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/AbstractLoRaPluginFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..d78e6234a22cb9180d2ee549092d5afa5e81ff29 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/AbstractLoRaPluginFactory.java @@ -0,0 +1,73 @@ +package org.briarproject.bramble.plugin.lora; + +import org.briarproject.bramble.api.battery.BatteryManager; +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.network.NetworkManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Backoff; +import org.briarproject.bramble.api.plugin.BackoffFactory; +import org.briarproject.bramble.api.plugin.PluginCallback; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin; +import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; +import org.briarproject.bramble.api.plugin.LoRaConstants; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; +import org.briarproject.bramble.api.system.WakefulIoExecutor; + +import java.io.File; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; +import javax.net.SocketFactory; + +import static java.util.logging.Level.INFO; +import static java.util.logging.Logger.getLogger; + +@Immutable +@NotNullByDefault +abstract class AbstractLoRaPluginFactory implements SimplexPluginFactory { + + protected static final Logger LOG = + getLogger(AbstractLoRaPluginFactory.class.getName()); + + protected final BackoffFactory backoffFactory; + protected final Clock clock; + protected final CryptoComponent crypto; + protected final Executor ioExecutor, wakefulIoExecutor; + + AbstractLoRaPluginFactory(Executor ioExecutor, + Executor wakefulIoExecutor,BackoffFactory backoffFactory, Clock clock, CryptoComponent crypto) { + this.backoffFactory = backoffFactory; + this.clock = clock; + this.crypto = crypto; + this.ioExecutor = ioExecutor; + this.wakefulIoExecutor = wakefulIoExecutor; + } + + abstract AbstractLoRaPlugin createPluginInstance(Backoff backoff, PluginCallback callback); + + @Override + public TransportId getId() { + return LoRaConstants.ID; + } + + @Override + public long getMaxLatency() { + return LoRaConstants.MAX_LATENCY; + } + + @Override + public SimplexPlugin createPlugin(PluginCallback callback) { + + Backoff backoff = backoffFactory.createBackoff(LoRaConstants.MIN_POLLING_INTERVAL, LoRaConstants.MAX_POLLING_INTERVAL, LoRaConstants.BACKOFF_BASE); + AbstractLoRaPlugin plugin = createPluginInstance(backoff, callback); + //eventBus.addListener(plugin); + return plugin; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/DeviceManager.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/DeviceManager.java new file mode 100644 index 0000000000000000000000000000000000000000..57de347b181b27a5b499cb8923ef08bac01e001c --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/DeviceManager.java @@ -0,0 +1,22 @@ +package org.briarproject.bramble.plugin.lora; + +import org.briarproject.bramble.plugin.lora.LoRaAdapter; +import org.briarproject.bramble.api.plugin.Plugin; +import static org.briarproject.bramble.api.plugin.Plugin.State.*; + +public class DeviceManager { + protected LoRaAdapter activeModule; + protected Plugin.State state = ACTIVE; //TODO + + public void setModule(LoRaAdapter module) { + this.activeModule = module; + } + + public LoRaAdapter getAdapter() { + return activeModule; + } + + public Plugin.State getState() { + return state; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PReader.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PReader.java new file mode 100644 index 0000000000000000000000000000000000000000..4ccca106d3fde2737879cc44cc5ffcd045dee620 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PReader.java @@ -0,0 +1,155 @@ +package org.briarproject.bramble.plugin.lora; + +import org.briarproject.bramble.plugin.lora.AbstractLoRaPlugin; +import org.briarproject.bramble.api.plugin.TransportConnectionReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.PipedOutputStream; +import java.io.PipedInputStream; +import org.briarproject.bramble.plugin.lora.LoRaAdapter; +import org.briarproject.bramble.plugin.lora.L2PReaderFactory; +import org.briarproject.bramble.util.ByteUtils; +import java.util.Arrays; +import java.lang.System; +import org.briarproject.bramble.api.Bytes; +import java.util.logging.Logger; +import java.util.concurrent.LinkedBlockingDeque; +import java.lang.InterruptedException; +import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; +import static org.briarproject.bramble.api.plugin.LoRaConstants.*; + +public class L2PReader implements TransportConnectionReader { + private L2PReaderFactory f; + private L2PInputStream stream = new L2PInputStream(this); + private Long nextSequenceNr = 0L; + + private static final Logger LOG = + Logger.getLogger(L2PReader.class.getName()); + + public L2PReader(L2PReaderFactory factory) { + f = factory; + } + + public void parse(byte content[], Bytes tag, long sequenceNR) { + LOG.info("reader pkg "+sequenceNR+" with tag "+ByteUtils.bytesToHex(tag.getBytes())+": "+ByteUtils.bytesToHex(content)); + + try { + //lost a Packet + if(sequenceNR != nextSequenceNr) { + //we don't have a better mechanism :( + LOG.info("read sequenceNr " + sequenceNR + " expected "+nextSequenceNr); + this.dispose(false, true); + } + + if(sequenceNR == 0) { + System.arraycopy(tag.getBytes(),0,content,0,TAG_LENGTH); + stream.add(content); + } else { + stream.add(Arrays.copyOfRange(content,TAG_LENGTH,PKG_SIZE)); + } + + nextSequenceNr++; + } catch (IOException e) { + // TODO + } + } + + @Override + public InputStream getInputStream() throws IOException { + return stream; + } + + @Override + public void dispose(boolean exception, boolean recognised) + throws IOException { + f.remove(this); + } + + //TODO: Syncronize + private class L2PInputStream extends InputStream { + private L2PReader r; + private LinkedBlockingDeque<Bytes> buffer = new LinkedBlockingDeque<>(); + private int offset = 0; + private boolean closed=false; + + public L2PInputStream(L2PReader r) { + this.r = r; + } + + public void add(byte n[]) { + buffer.offerLast(new Bytes(n)); + } + + //just use the parent wrapper + //@Override + //public int read(byte[] b) throws IOException + + //also just use parent wrapper + //public long skip(long n) throws IOException + + @Override + public int read() throws IOException { + if(buffer.size() == 0 && closed) + return -1; + int ret=0; + try { + Bytes block = buffer.take(); + ret = block.getBytes()[offset++]; + if(offset == block.getBytes().length) + offset = 0; + //next Block + else + buffer.putFirst(block); + } catch(InterruptedException e) { + } + + return ret; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if(buffer.size() == 0 && closed) { + return -1; + } + + int read=0; + try { + while(len > 0 && (buffer.size() > 0 || read == 0)) { + Bytes block = buffer.take(); + int l = Math.min(len, block.getBytes().length-offset); + System.arraycopy(block.getBytes(), offset, b, off, l); + offset += l; + off += l; + read += l; + len -= l; + if(offset >= block.getBytes().length) + offset = 0; + //discard block from buffer + else + buffer.putFirst(block); + } + } catch(InterruptedException e) { + } + + return read; + } + + @Override + public int available() throws IOException { + return (buffer.size()>0 && !closed)?PKG_SIZE-TAG_LENGTH:0; + } + + @Override + public void close() throws IOException { + closed=true; + buffer.offerLast(new Bytes(new byte[1])); //push dummy data (like padding) to the Reader to not lock the reader + r.dispose(false,false); + } + + //TODO: needed? + @Override + public boolean markSupported() { + return false; + } + } +} \ No newline at end of file diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PReaderFactory.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PReaderFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..2a28d60f2fc172ba41f16fe4a264d40737c657a7 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PReaderFactory.java @@ -0,0 +1,82 @@ +package org.briarproject.bramble.plugin.lora; + +import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; +import org.briarproject.bramble.plugin.lora.AbstractLoRaPlugin; +import org.briarproject.bramble.api.plugin.TransportConnectionReader; +import java.io.IOException; +import java.io.InputStream; +import org.briarproject.bramble.plugin.lora.LoRaAdapter; +import org.briarproject.bramble.plugin.lora.L2PReader; +import org.briarproject.bramble.plugin.lora.L2PTagManager; +import java.util.Arrays; +import java.lang.Integer; +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; +import java.util.logging.Logger; +import org.briarproject.bramble.util.ByteUtils; +import org.briarproject.bramble.api.Bytes; +import org.briarproject.bramble.api.Pair; +import org.briarproject.bramble.api.plugin.PluginCallback; +import org.briarproject.bramble.api.plugin.LoRaConstants; + +//TODO: Make singleton +public class L2PReaderFactory { + //TODO: Do I need syncronisation here? + private Map<Bytes, L2PReader> readers = Collections.synchronizedMap(new HashMap<Bytes, L2PReader>()); + + private PluginCallback callback; + private static final Logger LOG = + Logger.getLogger(L2PReaderFactory.class.getName()); + + private final L2PTagManager l2pTags; + + public L2PReaderFactory(PluginCallback callback) { + this.callback = callback; + l2pTags = L2PTagManager.TODOuseDependencyInjection(LoRaConstants.ID); + l2pTags.setOpenReaders(readers); + } + + private L2PReader createReader() { + L2PReader r = new L2PReader(this); + callback.handleReader(r); + return r; + } + + private L2PReader getReaderByBTPtag(Bytes btpTag) { + L2PReader r = readers.get(btpTag); + if(r == null) { + r = createReader(); + readers.put(btpTag, r); + } + + return r; + } + + public void parse(byte[] content) { + byte[] l2pTag = Arrays.copyOf(content, TAG_LENGTH); + Pair<Bytes,Long> tagData = l2pTags.get(new Bytes(l2pTag)); + if(tagData == null) { + //this packet isn't recognised => it probably is no briar packet => ignore + LOG.info("dropping LoRa pkg "+ByteUtils.bytesToHex(content)); + LOG.info("Tags:"+l2pTags.toString()); + return; + } + getReaderByBTPtag(tagData.getFirst()).parse(content, tagData.getFirst(), tagData.getSecond().intValue()); + + //TODO: Drop Tag if successfull! + + //generate next Tags + l2pTags.addNfromBTPtag(tagData.getFirst(), tagData.getSecond()+1, L2PTagManager.CALCULATE_OPEN_CONN); + } + + public void remove(L2PReader r) { + for(Entry<Bytes,L2PReader> i: readers.entrySet()) + if(r.equals(i.getValue())) { + Bytes BTPtag = i.getKey(); + readers.remove(BTPtag); + l2pTags.removeAllFromBTPtag(BTPtag); + return; + } + } +} \ No newline at end of file diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PTagManager.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PTagManager.java new file mode 100644 index 0000000000000000000000000000000000000000..f904152e6e472fef415b7e8fa5aa8ab7423fc6be --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PTagManager.java @@ -0,0 +1,137 @@ +package org.briarproject.bramble.plugin.lora; + +import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; +import org.briarproject.bramble.plugin.lora.AbstractLoRaPlugin; +import org.briarproject.bramble.api.plugin.TransportConnectionReader; +import java.io.IOException; +import java.io.InputStream; +import org.briarproject.bramble.plugin.lora.LoRaAdapter; +import org.briarproject.bramble.plugin.lora.L2PReader; +import java.util.Arrays; +import java.lang.Long; +import java.util.HashMap; +import java.util.Map; +import java.lang.System; +import java.util.Collections; +import java.util.logging.Logger; +import org.briarproject.bramble.util.ByteUtils; +import org.briarproject.bramble.api.Bytes; +import org.briarproject.bramble.api.Pair; +import org.briarproject.bramble.api.plugin.PluginCallback; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.plugin.LoRaConstants; +import org.briarproject.bramble.plugin.lora.L2PReader; +import org.briarproject.bramble.api.crypto.TransportCrypto; +import java.util.Map.Entry; +import java.util.Iterator; +import java.util.Collection; + +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.Blake2bDigest; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.nullsafety.NullSafety.requireExactlyOneNull; +import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; +import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION; +import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES; +import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; +import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED; +import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED; +import static org.briarproject.bramble.util.ByteUtils.writeUint16; +import static org.briarproject.bramble.util.ByteUtils.writeUint64; +import java.util.logging.Logger; + + + +public class L2PTagManager { + + private static final Logger LOG = + Logger.getLogger(L2PTagManager.class.getName()); + + + //TODO: For better performance, we should choose a data-structure that is indexed by B2PTag as well as L2PTag + private final Map<Bytes, Pair<Bytes,Long>> l2pTags = Collections.synchronizedMap(new HashMap<Bytes, Pair<Bytes,Long>>()); + private Map<Bytes, L2PReader> openReaders; +// private TransportCrypto crypto; //move genL2PTag to TransportCrypto + + public String toString() { + return l2pTags.toString(); + } + + //TODO: Evaluate what makes sense using a simple or sophisticated protocol + public static final int CALCULATE_STD = 4; + public static final int CALCULATE_OPEN_CONN = 16; + + public L2PTagManager() { + //Init crypto with TransportCryptoImpl including dependency injection + } + + public void addNfromBTPtag(final Bytes inTag, long start, int n) { + for(long i=start; i<start+n; i++) { + l2pTags.put(genL2PTag(inTag, i), new Pair<Bytes,Long>(inTag, i)); + } + } + + //Bytes: BTP-Tag, Integer: sequenceNR + public Pair<Bytes,Long> get(Bytes L2PTag) { + return l2pTags.get(L2PTag); + } + + public void remove(Bytes l2pTag) { + l2pTags.remove(l2pTag); + } + + public void removeAllFromBTPtag(Bytes inTag) { + if(openReaders.get(inTag) != null) + return; + + //TODO: More elegant option to remove Elements using lambda? + Iterator<Pair<Bytes, Long>> i = l2pTags.values().iterator(); + while(i.hasNext()) + if(inTag.equals(i.next().getSecond())) + i.remove(); + } + + public void clear() { + l2pTags.clear(); + } + + public void setOpenReaders(Map<Bytes, L2PReader> rs) { + this.openReaders = rs; + } + + public static Bytes genL2PTag(final Bytes inTag, long i) { + //I don't understand the 32 Bytes, I just copied it from TransportCryptoImpl ... + Digest prf = new Blake2bDigest(inTag.getBytes(), 32, null, null); + // The output of the PRF must be long enough to use as a tag + int macLength = prf.getDigestSize(); + if (macLength < TAG_LENGTH) throw new IllegalStateException(); + +// byte[] protocolVersionBytes = new byte[INT_16_BYTES]; +// writeUint16(protocolVersion, protocolVersionBytes, 0); +// prf.update(protocolVersionBytes, 0, protocolVersionBytes.length); + + //TODO: could break a stream after 2^62 frames - would be Zettabytes of data + byte[] sequenceNrBuffer = new byte[INT_64_BYTES]; + writeUint64(i, sequenceNrBuffer, 0); + prf.update(sequenceNrBuffer, 0, sequenceNrBuffer.length); + byte[] mac = new byte[macLength]; + prf.doFinal(mac, 0); + + // The output is the first TAG_LENGTH bytes of the MAC + byte[] tag = new byte[TAG_LENGTH]; + System.arraycopy(mac, 0, tag, 0, TAG_LENGTH); + return new Bytes(tag); + } + + //TODO: Move to Dependency Injection + private static final L2PTagManager m = new L2PTagManager(); + public static L2PTagManager TODOuseDependencyInjection(TransportId t) { + return m; + } +} \ No newline at end of file diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PWriter.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PWriter.java new file mode 100644 index 0000000000000000000000000000000000000000..e86ef37b98df838c9a0f3ea5b68e5149c5e9d568 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/L2PWriter.java @@ -0,0 +1,124 @@ +package org.briarproject.bramble.plugin.lora; + +import org.briarproject.bramble.plugin.lora.AbstractLoRaPlugin; +import org.briarproject.bramble.api.plugin.TransportConnectionWriter; +import java.io.IOException; +import java.io.OutputStream; +import org.briarproject.bramble.plugin.lora.LoRaAdapter; +import java.util.Arrays; +import java.lang.System; +import java.util.logging.Logger; +import org.briarproject.bramble.util.ByteUtils; +import org.briarproject.bramble.plugin.lora.L2PTagManager; +import org.briarproject.bramble.api.Bytes; + +import static org.briarproject.bramble.api.plugin.LoRaConstants.*; +import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; + +public class L2PWriter implements TransportConnectionWriter { + + private static final Logger LOG = + Logger.getLogger(L2PWriter.class.getName()); + + private AbstractLoRaPlugin plugin; + + L2PWriter(AbstractLoRaPlugin plugin) { + LOG.info("L2PWriter::Constructor"); + this.plugin = plugin; + } + + @Override + public long getMaxLatency() { + return plugin.getMaxLatency(); + } + + @Override + public int getMaxIdleTime() { + return plugin.getMaxIdleTime(); + } + + @Override + public boolean isLossyAndCheap() { + return false; + } + + @Override + public OutputStream getOutputStream() throws IOException { + return new L2OutputStream(plugin.getAdapter()); + } + + @Override + public void dispose(boolean exception) throws IOException { + } + + private class L2OutputStream extends OutputStream { + private LoRaAdapter adapter; + private byte[] buffer; + private byte[] btpTag = new byte[TAG_LENGTH]; + private short readTagLength=0; + private long sequenceNr=0; + + L2OutputStream(LoRaAdapter adapter) { + this.adapter = adapter; + buffer = new byte[0]; + } + + @Override + public void close() throws IOException { + flush(); + LOG.info("close()"); + } + + @Override + public void write(int b) throws IOException { + write(new byte[]{(byte)b}, 0, 1); + } + + @Override + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + //flush(); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + LOG.info("WRITE ("+len+" Bytes)"); + LOG.info(ByteUtils.bytesToHex(b)); + + //Read BTP-Tag first (if not done) and write it in another Array + while(readTagLength < TAG_LENGTH && len > 0) { + btpTag[readTagLength++] = b[off++]; + len--; + } + + if(len <= 0) //for speed + return; + + if(off != 0) { + byte tmp[] = new byte[len]; + System.arraycopy(b,off,tmp,0,len); + b = tmp; + } else if(b.length != len) + b = Arrays.copyOf(b,len); + + buffer = ByteUtils.concat(buffer, b); + while(buffer.length >= PAYLOAD_SIZE) { + flush(); + } + } + + @Override + public void flush() { + if(buffer.length != 0) { + int len = Math.min(PAYLOAD_SIZE, buffer.length); + + byte[] pkg = new byte[len+TAG_LENGTH]; + System.arraycopy(L2PTagManager.genL2PTag(new Bytes(btpTag), sequenceNr++).getBytes(), 0, pkg, 0, TAG_LENGTH); //Write L2PTag + System.arraycopy(buffer, 0, pkg, TAG_LENGTH, len); + adapter.send(pkg); + + buffer = Arrays.copyOfRange(buffer, len, buffer.length); + } + } + } +} \ No newline at end of file diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/LoRaAdapter.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/LoRaAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..29e48fcb832972d581d1d4eaa77ef16775e7c4fb --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/lora/LoRaAdapter.java @@ -0,0 +1,9 @@ +package org.briarproject.bramble.plugin.lora; + +import java.util.List; + +public interface LoRaAdapter { + public void send(byte[] payload); + public void start(); + public void stop(); +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java index 1b1764137e2f5c6825f0398bcc360afed77bc051..9622edd58ab0186bbe37403c4c7e2126aee6b0c0 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/KeyManagerImpl.java @@ -85,6 +85,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { try { db.transaction(false, txn -> { for (PluginFactory<?> f : pluginConfig.getSimplexFactories()) { + LOG.info("addTransport(...,"+f.getId()+")"); addTransport(txn, f); } for (PluginFactory<?> f : pluginConfig.getDuplexFactories()) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java index 788d51d3cac440fb4c9bd537008ac3661bee057a..dd41ea4988be0b6b225f4870080bc355701bd765 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/transport/TransportKeyManagerImpl.java @@ -19,6 +19,9 @@ import org.briarproject.bramble.api.transport.TransportKeySet; import org.briarproject.bramble.api.transport.TransportKeys; import org.briarproject.bramble.transport.ReorderingWindow.Change; import org.briarproject.nullsafety.NotNullByDefault; +import org.briarproject.bramble.util.ByteUtils; +import org.briarproject.bramble.plugin.lora.L2PTagManager; +import org.briarproject.bramble.api.plugin.LoRaConstants; import java.util.ArrayList; import java.util.Collection; @@ -72,6 +75,9 @@ class TransportKeyManagerImpl implements TransportKeyManager { private final Map<PendingContactId, MutableTransportKeySet> pendingContactOutContexts = new HashMap<>(); + @Nullable + private final L2PTagManager l2ptm; + TransportKeyManagerImpl(DatabaseComponent db, TransportCrypto transportCrypto, Executor dbExecutor, @@ -86,10 +92,17 @@ class TransportKeyManagerImpl implements TransportKeyManager { this.clock = clock; this.transportId = transportId; timePeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE; + + if(LoRaConstants.ID.equals(transportId)) + l2ptm = L2PTagManager.TODOuseDependencyInjection(LoRaConstants.ID); + else + l2ptm = null; } @Override public void start(Transaction txn) throws DbException { + LOG.info("TransportKeyManager::start()"); + if (used.getAndSet(true)) throw new IllegalStateException(); long now = clock.currentTimeMillis(); lock.lock(); @@ -97,13 +110,18 @@ class TransportKeyManagerImpl implements TransportKeyManager { // Load the transport keys from the DB Collection<TransportKeySet> loaded = db.getTransportKeys(txn, transportId); + LOG.info("loaded="+loaded); // Update the keys to the current time period UpdateResult updateResult = updateKeys(loaded, now); + LOG.info("updated="+updateResult.updated); // Initialise mutable state for all contacts addKeys(updateResult.current); // Write any updated keys back to the DB if (!updateResult.updated.isEmpty()) db.updateTransportKeys(txn, updateResult.updated); + } catch(Exception e) { + LOG.info(e.toString()); + throw e; } finally { lock.unlock(); } @@ -115,10 +133,12 @@ class TransportKeyManagerImpl implements TransportKeyManager { long now) { UpdateResult updateResult = new UpdateResult(); long timePeriod = now / timePeriodLength; + LOG.info("current timeperiod:"+timePeriod); for (TransportKeySet ks : keys) { TransportKeys k = ks.getKeys(); TransportKeys k1 = transportCrypto.updateTransportKeys(k, timePeriod); + LOG.info("k1:"+k1); if (k1.getTimePeriod() > k.getTimePeriod()) { TransportKeySet ks1 = new TransportKeySet(ks.getKeySetId(), ks.getContactId(), ks.getPendingContactId(), k1); @@ -168,7 +188,13 @@ class TransportKeyManagerImpl implements TransportKeyManager { byte[] tag = new byte[TAG_LENGTH]; transportCrypto.encodeTag(tag, inKeys.getTagKey(), PROTOCOL_VERSION, streamNumber); - inContexts.put(new Bytes(tag), tagCtx); + Bytes tagObj = new Bytes(tag); + inContexts.put(tagObj, tagCtx); + LOG.info("New Tag for "+contactId+" - "+streamNumber); + + + if(l2ptm != null) + l2ptm.addNfromBTPtag(tagObj, 0, L2PTagManager.CALCULATE_STD); } } @@ -292,6 +318,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { } } + //TODO: remove from L2PTagManager @Override public void removeContact(ContactId c) { lock.lock(); @@ -299,16 +326,19 @@ class TransportKeyManagerImpl implements TransportKeyManager { // Remove mutable state for the contact Iterator<TagContext> it = inContexts.values().iterator(); while (it.hasNext()) - if (c.equals(it.next().contactId)) it.remove(); + if (c.equals(it.next().contactId)) + it.remove(); contactOutContexts.remove(c); Iterator<MutableTransportKeySet> it1 = keys.values().iterator(); while (it1.hasNext()) - if (c.equals(it1.next().getContactId())) it1.remove(); + if (c.equals(it1.next().getContactId())) + it1.remove(); } finally { lock.unlock(); } } + //TODO: remove from L2PTagManager @Override public void removePendingContact(PendingContactId p) { lock.lock(); @@ -415,8 +445,10 @@ class TransportKeyManagerImpl implements TransportKeyManager { @GuardedBy("lock") @Nullable private StreamContext streamContextFromTag(byte[] tag) { + LOG.info("try to recognize tag "+ByteUtils.bytesToHex(tag)+" possibilities:"+inContexts.toString()); // Look up the incoming keys for the tag TagContext tagCtx = inContexts.get(new Bytes(tag)); + LOG.info("TagContext: "+(tagCtx!=null?tagCtx.toString():"null")); if (tagCtx == null) return null; MutableIncomingKeys inKeys = tagCtx.inKeys; // Create a stream context @@ -430,6 +462,7 @@ class TransportKeyManagerImpl implements TransportKeyManager { public void markTagAsRecognised(Transaction txn, byte[] tag) throws DbException { TagContext tagCtx = inContexts.remove(new Bytes(tag)); + //TODO: do nothing for L2PTagManager, or am I wrong? if (tagCtx == null) return; MutableIncomingKeys inKeys = tagCtx.inKeys; // Update the reordering window @@ -443,7 +476,13 @@ class TransportKeyManagerImpl implements TransportKeyManager { TagContext tagCtx1 = new TagContext(tagCtx.keySetId, tagCtx.contactId, tagCtx.pendingContactId, inKeys, streamNumber, tagCtx.handshakeMode); - inContexts.put(new Bytes(addTag), tagCtx1); + Bytes addTagObj = new Bytes(addTag); + inContexts.put(addTagObj, tagCtx1); + LOG.info("New Tag for "+tagCtx.contactId+" - "+streamNumber); + + + if(l2ptm != null) + l2ptm.addNfromBTPtag(addTagObj, 0, L2PTagManager.CALCULATE_STD); } // Remove tags for any stream numbers removed from the window for (long streamNumber : change.getRemoved()) { @@ -451,7 +490,11 @@ class TransportKeyManagerImpl implements TransportKeyManager { byte[] removeTag = new byte[TAG_LENGTH]; transportCrypto.encodeTag(removeTag, inKeys.getTagKey(), PROTOCOL_VERSION, streamNumber); - inContexts.remove(new Bytes(removeTag)); + Bytes removeTagObj = new Bytes(removeTag); + inContexts.remove(removeTagObj); + + if(l2ptm != null) + l2ptm.removeAllFromBTPtag(removeTagObj); } // Write the window back to the DB db.setReorderingWindow(txn, tagCtx.keySetId, transportId, @@ -488,6 +531,8 @@ class TransportKeyManagerImpl implements TransportKeyManager { contactOutContexts.clear(); pendingContactOutContexts.clear(); keys.clear(); + if(l2ptm != null) + l2ptm.clear(); addKeys(updateResult.current); // Write any updated keys back to the DB if (!updateResult.updated.isEmpty()) @@ -522,6 +567,11 @@ class TransportKeyManagerImpl implements TransportKeyManager { this.streamNumber = streamNumber; this.handshakeMode = handshakeMode; } + + public String toString() { + return "KeySetId: "+keySetId.getInt()+" streamNumber: "+streamNumber; + //+" ContactId: "+contactId.getInt()+" handshakeMode: "+handshakeMode+" PendingContactId: "+pendingContactId + } } private static class UpdateResult { diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/lora/UnixLoRaPlugin.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/lora/UnixLoRaPlugin.java new file mode 100644 index 0000000000000000000000000000000000000000..0ec2e705ab66deb196242b1b89dd80ca50099d38 --- /dev/null +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/lora/UnixLoRaPlugin.java @@ -0,0 +1,35 @@ +package org.briarproject.bramble.plugin.lora; + +import com.sun.jna.Library; +import com.sun.jna.Native; + +import org.briarproject.bramble.api.battery.BatteryManager; +import org.briarproject.bramble.api.network.NetworkManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Backoff; +import org.briarproject.bramble.api.plugin.PluginCallback; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; +import org.briarproject.bramble.plugin.lora.adapter.*; +import org.briarproject.bramble.plugin.lora.DeviceManager; + +import java.io.File; +import java.util.concurrent.Executor; + +import javax.net.SocketFactory; + +@NotNullByDefault +class UnixLoRaPlugin extends AbstractLoRaPlugin { + + UnixLoRaPlugin( + Executor ioExecutor, + Executor wakefulIoExecutor,Clock clock, + Backoff backoff, + PluginCallback callback, + long maxLatency, + int maxIdleTime) { + super(ioExecutor, wakefulIoExecutor,clock, backoff, callback, maxLatency, maxIdleTime); + devicemanager.setModule(new Pinedio(rf)); + } +} diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/lora/UnixLoRaPluginFactory.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/lora/UnixLoRaPluginFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..7721580fd10024c3d339113d254ec24cba4a4ddd --- /dev/null +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/lora/UnixLoRaPluginFactory.java @@ -0,0 +1,43 @@ +package org.briarproject.bramble.plugin.lora; + +import org.briarproject.bramble.api.battery.BatteryManager; +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.network.NetworkManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Backoff; +import org.briarproject.bramble.api.plugin.BackoffFactory; +import org.briarproject.bramble.api.plugin.PluginCallback; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; +import org.briarproject.bramble.api.system.WakefulIoExecutor; +import org.briarproject.bramble.plugin.lora.AbstractLoRaPluginFactory; +import org.briarproject.bramble.plugin.lora.AbstractLoRaPlugin; +import org.briarproject.bramble.api.plugin.LoRaConstants; + +import java.io.File; +import java.util.concurrent.Executor; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; +import javax.net.SocketFactory; + +import static java.util.logging.Level.INFO; + +@Immutable +@NotNullByDefault +public class UnixLoRaPluginFactory extends AbstractLoRaPluginFactory { + + @Inject + UnixLoRaPluginFactory(@IoExecutor Executor ioExecutor, @WakefulIoExecutor Executor wakefulIoExecutor,BackoffFactory backoffFactory, Clock clock, CryptoComponent crypto) { + super(ioExecutor, wakefulIoExecutor, backoffFactory, clock, crypto); + } + + @Override + AbstractLoRaPlugin createPluginInstance(Backoff backoff, PluginCallback callback) { + return new UnixLoRaPlugin(ioExecutor, wakefulIoExecutor, clock, backoff, callback, LoRaConstants.MAX_LATENCY, LoRaConstants.MAX_IDLE_TIME); + } +} diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/lora/adapter/Pinedio.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/lora/adapter/Pinedio.java new file mode 100644 index 0000000000000000000000000000000000000000..c15f105f663ee1699f4a7af302fd71e40d1092e5 --- /dev/null +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/lora/adapter/Pinedio.java @@ -0,0 +1,87 @@ +package org.briarproject.bramble.plugin.lora.adapter; + +import org.briarproject.bramble.plugin.lora.LoRaAdapter; +import org.briarproject.bramble.plugin.lora.L2PReaderFactory; + +import java.lang.System; +import java.security.SecureRandom; +import java.util.Arrays; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Platform; +import com.sun.jna.Callback; +import com.sun.jna.Pointer; +import org.briarproject.bramble.util.ByteUtils; + +import javax.inject.Inject; +import java.util.logging.Logger; + +public class Pinedio implements LoRaAdapter { + private final SecureRandom secureRandom; + private L2PReaderFactory rf; + + private static final Logger LOG = + Logger.getLogger(Pinedio.class.getName()); + + + private CLibrary.appRxCallback_ RxCallback = new CLibrary.appRxCallback_() { + public void invoke(Pointer payload, byte RssiPkt, byte SnrPkt, byte SignalRssiPkt) { + byte[] b = payload.getByteArray(0,255); + LOG.info("Rx "+ByteUtils.bytesToHex(b)); + + rf.parse(b); + } + }; + + private interface CLibrary extends Library { + CLibrary INSTANCE = (CLibrary)Native.loadLibrary("pinedio-lora-driver", CLibrary.class); + + interface appRxCallback_ extends Callback { + void invoke(Pointer payload, byte RssiPkt, byte SnrPkt, byte SignalRssiPkt); + } + + void PinedioLoraRadioInitialize(appRxCallback_ RxCallback); + void PinedioLoraRadioSend(byte payload[]); //make sure we have exactly 255 elements!! + void PinedioLoraRadioStart(); + void PinedioLoraRadioStop(); + } + +// @Inject + public Pinedio(L2PReaderFactory rf) { + this.rf = rf; + + this.secureRandom = new SecureRandom(); //TODO: Dependency Inection + System.setProperty("jna.debug_load", "true"); + System.setProperty("jna.library.path", "/root/Bakk2/briar/"); + + CLibrary.INSTANCE.PinedioLoraRadioInitialize(RxCallback); + //TODO: Stop + } + + public void start() { + CLibrary.INSTANCE.PinedioLoraRadioStart(); + } + + public void stop() { + CLibrary.INSTANCE.PinedioLoraRadioStop(); + } + + public void send(byte payload[]) { + //padding - the end of Stream is already known at a higher level so we can just add random chars + int length = payload.length; + if(length < 255) { + byte[] padding = new byte[255-length]; + secureRandom.nextBytes(padding); + + payload = Arrays.copyOf(payload, 255); + System.arraycopy(padding, 0, payload, length, 255-length); + } + + LOG.info("Tx " + ByteUtils.bytesToHex(payload)); + + CLibrary.INSTANCE.PinedioLoraRadioSend(payload); + } + + //TODO: Destructor +} \ No newline at end of file diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt index d15db40dd92716270eacb8dab8de80e33a859ca7..4a72b2f0290afffac891c3e97571c2cb2a1dfde8 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/HeadlessModule.kt @@ -20,6 +20,7 @@ import org.briarproject.bramble.battery.DefaultBatteryManagerModule import org.briarproject.bramble.event.DefaultEventExecutorModule import org.briarproject.bramble.plugin.tor.UnixTorPluginFactory import org.briarproject.bramble.plugin.tor.WindowsTorPluginFactory +import org.briarproject.bramble.plugin.lora.UnixLoRaPluginFactory import org.briarproject.bramble.system.ClockModule import org.briarproject.bramble.system.DefaultTaskSchedulerModule import org.briarproject.bramble.system.DefaultThreadFactoryModule @@ -92,16 +93,21 @@ internal class HeadlessModule(private val appDir: File) { @Singleton internal fun providePluginConfig( unixTor: UnixTorPluginFactory, - winTor: WindowsTorPluginFactory + winTor: WindowsTorPluginFactory, + unixlora: UnixLoRaPluginFactory ): PluginConfig { val duplex: List<DuplexPluginFactory> = when { isLinux() || isMac() -> listOf(unixTor) isWindows() -> listOf(winTor) else -> emptyList() } + var simplex: List<SimplexPluginFactory> = when { + isLinux() || isMac() -> listOf(unixLoRa) + else -> emptyList() + } return object : PluginConfig { override fun getDuplexFactories(): Collection<DuplexPluginFactory> = duplex - override fun getSimplexFactories(): Collection<SimplexPluginFactory> = emptyList() + override fun getSimplexFactories(): Collection<SimplexPluginFactory> = simplex override fun shouldPoll(): Boolean = true override fun getTransportPreferences(): Map<TransportId, List<TransportId>> = emptyMap() } diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/blogs/BlogControllerImpl.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/blogs/BlogControllerImpl.kt index 2df0d6dccfe32013212b32531ffc52daaa91d829..6c0b416539e00dfd4f1b1f6777ec41c1e5732790 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/blogs/BlogControllerImpl.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/blogs/BlogControllerImpl.kt @@ -49,7 +49,7 @@ constructor( val blog = blogManager.getPersonalBlog(author) val now = clock.currentTimeMillis() val post = blogPostFactory.createBlogPost(blog.id, now, null, author, text) - val header = db.transactionWithResult<BlogPostHeader, DbException>(true) { txn -> + val header = db.transactionWithResult<BlogPostHeader, DbException>(false) { txn -> blogManager.addLocalPost(txn, post) return@transactionWithResult blogManager.getPostHeader(txn, blog.id, post.message.id) }