diff --git a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataFileListManager.java b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataFileListManager.java index 87620128..a521922c 100644 --- a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataFileListManager.java +++ b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataFileListManager.java @@ -472,14 +472,22 @@ public class ArbitraryDataFileListManager { if (!isBlocked) { Peer requestingPeer = request.getB(); if (requestingPeer != null) { + Long requestTime = arbitraryDataFileListMessage.getRequestTime(); + Integer requestHops = arbitraryDataFileListMessage.getRequestHops(); + // Add each hash to our local mapping so we know who to ask later Long now = NTP.getTime(); for (byte[] hash : hashes) { String hash58 = Base58.encode(hash); - ArbitraryRelayInfo relayMap = new ArbitraryRelayInfo(hash58, signature58, peer, now); + ArbitraryRelayInfo relayMap = new ArbitraryRelayInfo(hash58, signature58, peer, now, requestTime, requestHops); ArbitraryDataFileManager.getInstance().addToRelayMap(relayMap); } + // Bump requestHops if it exists + if (requestHops != null) { + arbitraryDataFileListMessage.setRequestHops(++requestHops); + } + // Forward to requesting peer LOGGER.debug("Forwarding file list with {} hashes to requesting peer: {}", hashes.size(), requestingPeer); if (!requestingPeer.sendMessage(arbitraryDataFileListMessage)) { @@ -582,7 +590,9 @@ public class ArbitraryDataFileListManager { arbitraryDataFileListRequests.put(message.getId(), newEntry); } - ArbitraryDataFileListMessage arbitraryDataFileListMessage = new ArbitraryDataFileListMessage(signature, hashes); + String ourAddress = Network.getInstance().getOurExternalIpAddress(); + ArbitraryDataFileListMessage arbitraryDataFileListMessage = new ArbitraryDataFileListMessage(signature, + hashes, NTP.getTime(), 0, ourAddress, true); arbitraryDataFileListMessage.setId(message.getId()); if (!peer.sendMessage(arbitraryDataFileListMessage)) { LOGGER.debug("Couldn't send list of hashes"); diff --git a/src/main/java/org/qortal/data/arbitrary/ArbitraryRelayInfo.java b/src/main/java/org/qortal/data/arbitrary/ArbitraryRelayInfo.java index 94f41d18..17c1acac 100644 --- a/src/main/java/org/qortal/data/arbitrary/ArbitraryRelayInfo.java +++ b/src/main/java/org/qortal/data/arbitrary/ArbitraryRelayInfo.java @@ -9,12 +9,16 @@ public class ArbitraryRelayInfo { private final String signature58; private final Peer peer; private final Long timestamp; + private final Long requestTime; + private final Integer requestHops; - public ArbitraryRelayInfo(String hash58, String signature58, Peer peer, Long timestamp) { + public ArbitraryRelayInfo(String hash58, String signature58, Peer peer, Long timestamp, Long requestTime, Integer requestHops) { this.hash58 = hash58; this.signature58 = signature58; this.peer = peer; this.timestamp = timestamp; + this.requestTime = requestTime; + this.requestHops = requestHops; } public boolean isValid() { @@ -38,6 +42,14 @@ public class ArbitraryRelayInfo { return timestamp; } + public Long getRequestTime() { + return this.requestTime; + } + + public Integer getRequestHops() { + return this.requestHops; + } + @Override public String toString() { return String.format("%s = %s, %s, %d", this.hash58, this.signature58, this.peer, this.timestamp); diff --git a/src/main/java/org/qortal/network/Network.java b/src/main/java/org/qortal/network/Network.java index 6a5177ad..5de0b84d 100644 --- a/src/main/java/org/qortal/network/Network.java +++ b/src/main/java/org/qortal/network/Network.java @@ -1195,6 +1195,11 @@ public class Network { //ArbitraryDataManager.getInstance().broadcastHostedSignatureList(); } + public String getOurExternalIpAddress() { + // FUTURE: replace port if UPnP is active, as it will be more accurate + return this.ourExternalIpAddress; + } + // Peer-management calls diff --git a/src/main/java/org/qortal/network/message/ArbitraryDataFileListMessage.java b/src/main/java/org/qortal/network/message/ArbitraryDataFileListMessage.java index 008b3edd..3eef284f 100644 --- a/src/main/java/org/qortal/network/message/ArbitraryDataFileListMessage.java +++ b/src/main/java/org/qortal/network/message/ArbitraryDataFileListMessage.java @@ -1,6 +1,8 @@ package org.qortal.network.message; import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import org.qortal.data.network.PeerData; import org.qortal.transform.TransformationException; import org.qortal.transform.Transformer; import org.qortal.utils.Serialization; @@ -16,22 +18,38 @@ public class ArbitraryDataFileListMessage extends Message { private static final int SIGNATURE_LENGTH = Transformer.SIGNATURE_LENGTH; private static final int HASH_LENGTH = Transformer.SHA256_LENGTH; + private static final int MAX_PEER_ADDRESS_LENGTH = PeerData.MAX_PEER_ADDRESS_SIZE; private final byte[] signature; private final List hashes; + private final Long requestTime; + private Integer requestHops; + private final String peerAddress; + private final boolean isRelayPossible; - public ArbitraryDataFileListMessage(byte[] signature, List hashes) { + + public ArbitraryDataFileListMessage(byte[] signature, List hashes, Long requestTime, + Integer requestHops, String peerAddress, boolean isRelayPossible) { super(MessageType.ARBITRARY_DATA_FILE_LIST); this.signature = signature; this.hashes = hashes; + this.requestTime = requestTime; + this.requestHops = requestHops; + this.peerAddress = peerAddress; + this.isRelayPossible = isRelayPossible; } - public ArbitraryDataFileListMessage(int id, byte[] signature, List hashes) { + public ArbitraryDataFileListMessage(int id, byte[] signature, List hashes, Long requestTime, + Integer requestHops, String peerAddress, boolean isRelayPossible) { super(id, MessageType.ARBITRARY_DATA_FILE_LIST); this.signature = signature; this.hashes = hashes; + this.requestTime = requestTime; + this.requestHops = requestHops; + this.peerAddress = peerAddress; + this.isRelayPossible = isRelayPossible; } public List getHashes() { @@ -48,9 +66,6 @@ public class ArbitraryDataFileListMessage extends Message { int count = bytes.getInt(); - if (bytes.remaining() != count * HASH_LENGTH) - return null; - List hashes = new ArrayList<>(); for (int i = 0; i < count; ++i) { @@ -59,7 +74,26 @@ public class ArbitraryDataFileListMessage extends Message { hashes.add(hash); } - return new ArbitraryDataFileListMessage(id, signature, hashes); + Long requestTime = null; + Integer requestHops = null; + String peerAddress = null; + boolean isRelayPossible = true; // Legacy versions only send this message when relaying is possible + + // The remaining fields are optional + + if (bytes.hasRemaining()) { + + requestTime = bytes.getLong(); + + requestHops = bytes.getInt(); + + peerAddress = Serialization.deserializeSizedStringV2(bytes, MAX_PEER_ADDRESS_LENGTH); + + isRelayPossible = bytes.getInt() > 0; + + } + + return new ArbitraryDataFileListMessage(id, signature, hashes, requestTime, requestHops, peerAddress, isRelayPossible); } @Override @@ -75,6 +109,20 @@ public class ArbitraryDataFileListMessage extends Message { bytes.write(hash); } + if (this.requestTime == null) { // Just in case + return bytes.toByteArray(); + } + + // The remaining fields are optional + + bytes.write(Longs.toByteArray(this.requestTime)); + + bytes.write(Ints.toByteArray(this.requestHops)); + + Serialization.serializeSizedStringV2(bytes, this.peerAddress); + + bytes.write(Ints.toByteArray(this.isRelayPossible ? 1 : 0)); + return bytes.toByteArray(); } catch (IOException e) { return null; @@ -82,9 +130,30 @@ public class ArbitraryDataFileListMessage extends Message { } public ArbitraryDataFileListMessage cloneWithNewId(int newId) { - ArbitraryDataFileListMessage clone = new ArbitraryDataFileListMessage(this.signature, this.hashes); + ArbitraryDataFileListMessage clone = new ArbitraryDataFileListMessage(this.signature, this.hashes, + this.requestTime, this.requestHops, this.peerAddress, this.isRelayPossible); clone.setId(newId); return clone; } + public Long getRequestTime() { + return this.requestTime; + } + + public Integer getRequestHops() { + return this.requestHops; + } + + public void setRequestHops(int requestHops) { + this.requestHops = requestHops; + } + + public String getPeerAddress() { + return this.peerAddress; + } + + public boolean isRelayPossible() { + return this.isRelayPossible; + } + }