Fixed a few problems:

- some bugs that creeped in when I moved security into its own adapter
- improved some DB code as it doesn't work in Android anyway
- all entities should be serializable (very useful in Android)
This commit is contained in:
2015-08-28 13:48:01 +02:00
parent 4911c268c2
commit f89d1a342e
20 changed files with 83 additions and 38 deletions

View File

@ -81,7 +81,7 @@ public class InternalContext {
streams.add(1L);
}
init(inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkEngine);
init(inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkEngine, security);
}
private void init(Object... objects) {

View File

@ -19,9 +19,9 @@ package ch.dissem.bitmessage.entity;
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.ports.Security;
import ch.dissem.bitmessage.utils.Decode;
import ch.dissem.bitmessage.utils.Encode;
import ch.dissem.bitmessage.utils.UnixTime;
import java.io.*;
import java.util.*;
@ -29,7 +29,7 @@ import java.util.*;
/**
* The unencrypted message to be sent by 'msg' or 'broadcast'.
*/
public class Plaintext implements Streamable, Serializable {
public class Plaintext implements Streamable {
private final Type type;
private final BitmessageAddress from;
private final long encoding;
@ -64,6 +64,7 @@ public class Plaintext implements Streamable, Serializable {
public static Plaintext read(Type type, InputStream in) throws IOException {
return readWithoutSignature(type, in)
.signature(Decode.varBytes(in))
.received(UnixTime.now())
.build();
}
@ -132,6 +133,15 @@ public class Plaintext implements Streamable, Serializable {
this.signature = signature;
}
public boolean isUnread() {
for (Label label : labels) {
if (label.getType() == Label.Type.UNREAD) {
return true;
}
}
return false;
}
public void write(OutputStream out, boolean includeSignature) throws IOException {
Encode.varInt(from.getVersion(), out);
Encode.varInt(from.getStream(), out);

View File

@ -16,14 +16,13 @@
package ch.dissem.bitmessage.entity;
import ch.dissem.bitmessage.ports.Security;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
/**
* An object that can be written to an {@link OutputStream}
*/
public interface Streamable {
public interface Streamable extends Serializable {
void write(OutputStream stream) throws IOException;
}

View File

@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.Streamable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
/**
* The payload of an 'object' command. This is shared by the network.

View File

@ -16,9 +16,10 @@
package ch.dissem.bitmessage.entity.valueobject;
import java.io.Serializable;
import java.util.Objects;
public class Label {
public class Label implements Serializable {
private Object id;
private String label;
private Type type;

View File

@ -0,0 +1,114 @@
/*
* Copyright 2015 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.bitmessage.ports;
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
import ch.dissem.bitmessage.utils.UnixTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static ch.dissem.bitmessage.utils.Collections.selectRandom;
import static ch.dissem.bitmessage.utils.UnixTime.HOUR;
import static java.util.Collections.newSetFromMap;
public class MemoryNodeRegistry implements NodeRegistry {
private static final Logger LOG = LoggerFactory.getLogger(MemoryNodeRegistry.class);
private final Map<Long, Set<NetworkAddress>> stableNodes = new HashMap<>();
private final Map<Long, Set<NetworkAddress>> knownNodes = new ConcurrentHashMap<>();
public MemoryNodeRegistry() {
try (InputStream in = getClass().getClassLoader().getResourceAsStream("nodes.txt")) {
Scanner scanner = new Scanner(in);
long stream = 0;
Set<NetworkAddress> streamSet = null;
while (scanner.hasNext()) {
try {
String line = scanner.nextLine().trim();
if (line.startsWith("#") || line.isEmpty()) {
// Ignore
continue;
}
if (line.startsWith("[stream")) {
stream = Long.parseLong(line.substring(8, line.lastIndexOf(']')));
streamSet = new HashSet<>();
stableNodes.put(stream, streamSet);
} else if (streamSet != null) {
int portIndex = line.lastIndexOf(':');
InetAddress inetAddress = InetAddress.getByName(line.substring(0, portIndex));
int port = Integer.valueOf(line.substring(portIndex + 1));
streamSet.add(new NetworkAddress.Builder().ip(inetAddress).port(port).stream(stream).build());
}
} catch (IOException e) {
LOG.warn(e.getMessage(), e);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
List<NetworkAddress> result = new LinkedList<>();
for (long stream : streams) {
Set<NetworkAddress> known = knownNodes.get(stream);
if (known != null && !known.isEmpty()) {
for (NetworkAddress node : known) {
if (node.getTime() > UnixTime.now(-3 * HOUR)) {
result.add(node);
} else {
known.remove(node);
}
}
} else if (stableNodes.containsKey(stream)) {
// To reduce load on stable nodes, only return one
result.add(selectRandom(stableNodes.get(stream)));
}
}
return selectRandom(limit, result);
}
@Override
public void offerAddresses(List<NetworkAddress> addresses) {
for (NetworkAddress node : addresses) {
if (node.getTime() <= UnixTime.now()) {
if (!knownNodes.containsKey(node.getStream())) {
synchronized (knownNodes) {
if (!knownNodes.containsKey(node.getStream())) {
knownNodes.put(
node.getStream(),
newSetFromMap(new ConcurrentHashMap<NetworkAddress, Boolean>())
);
}
}
}
if (node.getTime() <= UnixTime.now()) {
// TODO: This isn't quite correct
// If the node is already known, the one with the more recent time should be used
knownNodes.get(node.getStream()).add(node);
}
}
}
}
}

View File

@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.utils.Property;
import java.io.IOException;
import java.net.InetAddress;
/**
* Handles incoming messages
@ -30,6 +31,8 @@ public interface NetworkHandler {
void stop();
void synchronize(InetAddress trustedHost, int port, MessageListener listener) throws IOException;
void offer(InventoryVector iv);
Property getNetworkStatus();

View File

@ -16,12 +16,6 @@
package ch.dissem.bitmessage.utils;
import ch.dissem.bitmessage.entity.Streamable;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
/**
* A helper class for working with byte arrays interpreted as unsigned big endian integers.
* This is one part due to the fact that Java doesn't support unsigned numbers, and another
@ -91,6 +85,8 @@ public class Bytes {
if (a < 0) return b < 0 && a < b;
if (b < 0) return a >= 0 || a < b;
return a < b;
// This would be easier to understand, but is (slightly) slower:
// return (a & 0xff) < (b & 0xff);
}
/**

View File

@ -117,6 +117,8 @@ public class Encode {
* @throws IOException if an I/O error occurs.
*/
public static byte[] bytes(Streamable streamable) throws IOException {
if (streamable == null) return null;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
streamable.write(stream);
return stream.toByteArray();

View File

@ -0,0 +1,15 @@
[stream 1]
[2604:2000:1380:9f:82e:148b:2746:d0c7]:8080
5.45.99.75:8444
75.167.159.54:8444
95.165.168.168:8444
85.180.139.241:8444
158.222.211.81:8080
178.62.12.187:8448
24.188.198.204:8111
109.147.204.113:1195
178.11.46.221:8444
[stream 2]
# none yet

View File

@ -17,21 +17,21 @@
package ch.dissem.bitmessage.entity;
import ch.dissem.bitmessage.entity.payload.*;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.utils.TestBase;
import ch.dissem.bitmessage.utils.TestUtils;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.util.Arrays;
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class SerializationTest {
public class SerializationTest extends TestBase {
@Test
public void ensureGetPubkeyIsDeserializedAndSerializedCorrectly() throws IOException {
doTest("V2GetPubkey.payload", 2, GetPubkey.class);
@ -75,7 +75,7 @@ public class SerializationTest {
}
@Test
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws IOException, DecryptionFailedException {
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws Exception {
Plaintext p1 = new Plaintext.Builder(MSG)
.from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
.to(TestUtils.loadContact())
@ -99,4 +99,21 @@ public class SerializationTest {
assertArrayEquals(data, out.toByteArray());
assertEquals(expectedPayloadType.getCanonicalName(), object.getPayload().getClass().getCanonicalName());
}
@Test
public void ensureSystemSerializationWorks() throws Exception {
Plaintext plaintext = new Plaintext.Builder(MSG)
.from(TestUtils.loadContact())
.to(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
.labels(Arrays.asList(new Label("Test", Label.Type.INBOX, 0)))
.message("Test", "Test Test.\nTest")
.build();
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(plaintext);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(in);
assertEquals(plaintext, ois.readObject());
}
}