Add AuthenticationListener

This commit is contained in:
Manfred Karrer 2015-12-22 10:39:59 +01:00
parent 2d518f9a16
commit 0d751eb561
7 changed files with 243 additions and 247 deletions

View file

@ -15,6 +15,7 @@ import io.bitsquare.crypto.EncryptionService;
import io.bitsquare.crypto.SealedAndSignedMessage; import io.bitsquare.crypto.SealedAndSignedMessage;
import io.bitsquare.p2p.messaging.*; import io.bitsquare.p2p.messaging.*;
import io.bitsquare.p2p.network.*; import io.bitsquare.p2p.network.*;
import io.bitsquare.p2p.peers.AuthenticationListener;
import io.bitsquare.p2p.peers.PeerGroup; import io.bitsquare.p2p.peers.PeerGroup;
import io.bitsquare.p2p.peers.RequestDataManager; import io.bitsquare.p2p.peers.RequestDataManager;
import io.bitsquare.p2p.seed.SeedNodesRepository; import io.bitsquare.p2p.seed.SeedNodesRepository;
@ -41,17 +42,15 @@ import java.util.concurrent.CopyOnWriteArraySet;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
public class P2PService implements SetupListener, MessageListener, ConnectionListener, HashMapChangedListener { public class P2PService implements SetupListener, MessageListener, ConnectionListener, HashMapChangedListener, AuthenticationListener {
private static final Logger log = LoggerFactory.getLogger(P2PService.class); private static final Logger log = LoggerFactory.getLogger(P2PService.class);
private final SeedNodesRepository seedNodesRepository; private final SeedNodesRepository seedNodesRepository;
private final int port; private final int port;
private final File torDir; private final File torDir;
private final boolean useLocalhost; private final boolean useLocalhost;
@Nullable private final Optional<EncryptionService> optionalEncryptionService;
private final EncryptionService encryptionService; private final Optional<KeyRing> optionalKeyRing;
@Nullable
private final KeyRing keyRing;
// set in init // set in init
private NetworkNode networkNode; private NetworkNode networkNode;
@ -96,8 +95,9 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
this.port = port; this.port = port;
this.torDir = torDir; this.torDir = torDir;
this.useLocalhost = useLocalhost; this.useLocalhost = useLocalhost;
this.encryptionService = encryptionService;
this.keyRing = keyRing; optionalEncryptionService = encryptionService == null ? Optional.empty() : Optional.of(encryptionService);
optionalKeyRing = keyRing == null ? Optional.empty() : Optional.of(keyRing);
dbStorage = new Storage<>(storageDir); dbStorage = new Storage<>(storageDir);
@ -131,6 +131,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
// peer group // peer group
peerGroup = new PeerGroup(networkNode); peerGroup = new PeerGroup(networkNode);
peerGroup.addAuthenticationListener(this);
if (useLocalhost) if (useLocalhost)
PeerGroup.setSimulateAuthTorNode(200); PeerGroup.setSimulateAuthTorNode(200);
@ -138,7 +139,23 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
dataStorage = new P2PDataStorage(peerGroup, storageDir); dataStorage = new P2PDataStorage(peerGroup, storageDir);
dataStorage.addHashMapChangedListener(this); dataStorage.addHashMapChangedListener(this);
// Request initial data manager
requestDataManager = new RequestDataManager(networkNode, dataStorage, new RequestDataManager.Listener() {
@Override
public void onNoSeedNodeAvailable() {
p2pServiceListeners.stream().forEach(e -> e.onNoSeedNodeAvailable());
}
@Override
public void onDataReceived(Address seedNode) {
connectedSeedNode = seedNode;
requestingDataCompleted.set(true);
p2pServiceListeners.stream().forEach(e -> e.onRequestingDataCompleted());
}
});
peerGroup.addAuthenticationListener(requestDataManager);
// Test multiple states to check when we are ready for authenticateSeedNode
readyForAuthentication = EasyBind.combine(hiddenServicePublished, requestingDataCompleted, firstPeerAuthenticated, readyForAuthentication = EasyBind.combine(hiddenServicePublished, requestingDataCompleted, firstPeerAuthenticated,
(hiddenServicePublished, requestingDataCompleted, firstPeerAuthenticated) (hiddenServicePublished, requestingDataCompleted, firstPeerAuthenticated)
-> hiddenServicePublished && requestingDataCompleted && !firstPeerAuthenticated); -> hiddenServicePublished && requestingDataCompleted && !firstPeerAuthenticated);
@ -157,7 +174,10 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
public void startAsSeedNode(Address mySeedNodeAddress, @Nullable P2PServiceListener listener) { public void startAsSeedNode(Address mySeedNodeAddress, @Nullable P2PServiceListener listener) {
Log.traceCall(); Log.traceCall();
// we remove ourselves from the list of seed nodes
seedNodeAddresses.remove(mySeedNodeAddress); seedNodeAddresses.remove(mySeedNodeAddress);
start(listener); start(listener);
} }
@ -199,33 +219,30 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
} }
/**
* Bootstrap sequence:
* <p>
* Variant 1 (normal expected mode):
* onTorNodeReady -> requestDataManager.requestData()
* RequestDataManager.Listener.onDataReceived && onHiddenServicePublished -> authenticateSeedNode()
* RequestDataManager.onPeerAddressAuthenticated -> RequestDataManager.requestDataFromAuthenticatedSeedNode()
* <p>
* Variant 2 (no seed node available):
* onTorNodeReady -> requestDataManager.requestData
* RequestDataManager.Listener.onNoSeedNodeAvailable && onHiddenServicePublished -> retry after 20-30 until
* seed node is available and data can be retrieved
* RequestDataManager.Listener.onDataReceived && onHiddenServicePublished -> authenticateSeedNode()
* RequestDataManager.onPeerAddressAuthenticated -> RequestDataManager.requestDataFromAuthenticatedSeedNode()
*/
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// SetupListener implementation // SetupListener implementation
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
public void onTorNodeReady() { public void onTorNodeReady() {
Log.traceCall(); Log.traceCall();
p2pServiceListeners.stream().forEach(e -> e.onTorNodeReady());
// 1. Step: As soon we have the tor node ready (hidden service still not available) we request the
// data set from a random seed node.
requestDataManager = new RequestDataManager(networkNode, dataStorage, new RequestDataManager.Listener() {
@Override
public void onNoSeedNodeAvailable() {
// 2b. or 3b Step: If no seed node available we keep trying again after a random pause
p2pServiceListeners.stream().forEach(e -> e.onNoSeedNodeAvailable());
}
@Override
public void onDataReceived(Address seedNode) {
// 2a. or 3a Step: We received initial data set
connectedSeedNode = seedNode;
requestingDataCompleted.set(true);
p2pServiceListeners.stream().forEach(e -> e.onRequestingDataCompleted());
}
});
requestDataManager.requestData(seedNodeAddresses); requestDataManager.requestData(seedNodeAddresses);
p2pServiceListeners.stream().forEach(e -> e.onTorNodeReady());
} }
@Override @Override
@ -240,7 +257,6 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
dbStorage.queueUpForSave(myOnionAddress); dbStorage.queueUpForSave(myOnionAddress);
} }
// 3. (or 2.). Step: Hidden service is published
hiddenServicePublished.set(true); hiddenServicePublished.set(true);
p2pServiceListeners.stream().forEach(e -> e.onHiddenServicePublished()); p2pServiceListeners.stream().forEach(e -> e.onHiddenServicePublished());
@ -252,14 +268,53 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
p2pServiceListeners.stream().forEach(e -> e.onSetupFailed(throwable)); p2pServiceListeners.stream().forEach(e -> e.onSetupFailed(throwable));
} }
// 4. Step: hiddenServicePublished and requestingDataCompleted. We start authenticate to the connected seed node.
private void authenticateSeedNode() { private void authenticateSeedNode() {
Log.traceCall(); Log.traceCall();
checkNotNull(connectedSeedNode != null, "connectedSeedNode must not be null"); checkNotNull(connectedSeedNode != null, "connectedSeedNode must not be null");
peerGroup.authenticateSeedNode(connectedSeedNode); peerGroup.authenticateSeedNode(connectedSeedNode);
} }
// 5. Step: in RequestDataManager (after authentication to first seed node we request again the data)
///////////////////////////////////////////////////////////////////////////////////////////
// ConnectionListener implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onConnection(Connection connection) {
}
@Override
public void onDisconnect(Reason reason, Connection connection) {
Log.traceCall();
if (connection.isAuthenticated())
authenticatedPeerAddresses.remove(connection.getPeerAddress());
numAuthenticatedPeers.set(authenticatedPeerAddresses.size());
}
@Override
public void onError(Throwable throwable) {
}
///////////////////////////////////////////////////////////////////////////////////////////
// AuthenticationListener implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onPeerAddressAuthenticated(Address peerAddress, Connection connection) {
Log.traceCall();
checkArgument(peerAddress.equals(connection.getPeerAddress()),
"peerAddress must match connection.getPeerAddress()");
authenticatedPeerAddresses.add(peerAddress);
if (!firstPeerAuthenticated.get()) {
firstPeerAuthenticated.set(true);
p2pServiceListeners.stream().forEach(e -> e.onFirstPeerAuthenticated());
}
numAuthenticatedPeers.set(authenticatedPeerAddresses.size());
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -271,11 +326,11 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
if (message instanceof SealedAndSignedMessage) { if (message instanceof SealedAndSignedMessage) {
Log.traceCall(message.toString()); Log.traceCall(message.toString());
// Seed nodes don't have set the encryptionService // Seed nodes don't have set the encryptionService
if (encryptionService != null) { if (optionalEncryptionService.isPresent()) {
try { try {
SealedAndSignedMessage sealedAndSignedMessage = (SealedAndSignedMessage) message; SealedAndSignedMessage sealedAndSignedMessage = (SealedAndSignedMessage) message;
if (verifyAddressPrefixHash(sealedAndSignedMessage)) { if (verifyAddressPrefixHash(sealedAndSignedMessage)) {
DecryptedMsgWithPubKey decryptedMsgWithPubKey = encryptionService.decryptAndVerify( DecryptedMsgWithPubKey decryptedMsgWithPubKey = optionalEncryptionService.get().decryptAndVerify(
sealedAndSignedMessage.sealedAndSigned); sealedAndSignedMessage.sealedAndSigned);
// We set connectionType to that connection to avoid that is get closed when // We set connectionType to that connection to avoid that is get closed when
@ -298,46 +353,10 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
} }
///////////////////////////////////////////////////////////////////////////////////////////
// ConnectionListener implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onConnection(Connection connection) {
}
@Override
public void onPeerAddressAuthenticated(Address peerAddress, Connection connection) {
Log.traceCall();
checkArgument(peerAddress.equals(connection.getPeerAddress()),
"peerAddress must match connection.getPeerAddress()");
authenticatedPeerAddresses.add(peerAddress);
if (!firstPeerAuthenticated.get()) {
firstPeerAuthenticated.set(true);
p2pServiceListeners.stream().forEach(e -> e.onFirstPeerAuthenticated());
}
numAuthenticatedPeers.set(authenticatedPeerAddresses.size());
}
@Override
public void onDisconnect(Reason reason, Connection connection) {
Log.traceCall();
if (connection.isAuthenticated())
authenticatedPeerAddresses.remove(connection.getPeerAddress());
numAuthenticatedPeers.set(authenticatedPeerAddresses.size());
}
@Override
public void onError(Throwable throwable) {
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// HashMapChangedListener implementation // HashMapChangedListener implementation
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
public void onAdded(ProtectedData entry) { public void onAdded(ProtectedData entry) {
if (entry instanceof ProtectedMailboxData) if (entry instanceof ProtectedMailboxData)
@ -370,10 +389,10 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
private void doSendEncryptedMailMessage(Address peerAddress, PubKeyRing pubKeyRing, MailMessage message, private void doSendEncryptedMailMessage(Address peerAddress, PubKeyRing pubKeyRing, MailMessage message,
SendMailMessageListener sendMailMessageListener) { SendMailMessageListener sendMailMessageListener) {
Log.traceCall(); Log.traceCall();
if (encryptionService != null) { checkArgument(optionalEncryptionService.isPresent(), "EncryptionService not set. Seems that is called on a seed node which must not happen.");
try { try {
SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage( SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(
encryptionService.encryptAndSign(pubKeyRing, message), peerAddress.getAddressPrefixHash()); optionalEncryptionService.get().encryptAndSign(pubKeyRing, message), peerAddress.getAddressPrefixHash());
SettableFuture<Connection> future = networkNode.sendMessage(peerAddress, sealedAndSignedMessage); SettableFuture<Connection> future = networkNode.sendMessage(peerAddress, sealedAndSignedMessage);
Futures.addCallback(future, new FutureCallback<Connection>() { Futures.addCallback(future, new FutureCallback<Connection>() {
@Override @Override
@ -392,7 +411,6 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
sendMailMessageListener.onFault(); sendMailMessageListener.onFault();
} }
} }
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -400,7 +418,8 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void processProtectedMailboxData(ProtectedMailboxData mailboxData) { private void processProtectedMailboxData(ProtectedMailboxData mailboxData) {
if (encryptionService != null) { // Seed nodes don't have set the encryptionService
if (optionalEncryptionService.isPresent()) {
Log.traceCall(); Log.traceCall();
ExpirablePayload expirablePayload = mailboxData.expirablePayload; ExpirablePayload expirablePayload = mailboxData.expirablePayload;
if (expirablePayload instanceof ExpirableMailboxPayload) { if (expirablePayload instanceof ExpirableMailboxPayload) {
@ -408,7 +427,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
SealedAndSignedMessage sealedAndSignedMessage = expirableMailboxPayload.sealedAndSignedMessage; SealedAndSignedMessage sealedAndSignedMessage = expirableMailboxPayload.sealedAndSignedMessage;
if (verifyAddressPrefixHash(sealedAndSignedMessage)) { if (verifyAddressPrefixHash(sealedAndSignedMessage)) {
try { try {
DecryptedMsgWithPubKey decryptedMsgWithPubKey = encryptionService.decryptAndVerify( DecryptedMsgWithPubKey decryptedMsgWithPubKey = optionalEncryptionService.get().decryptAndVerify(
sealedAndSignedMessage.sealedAndSigned); sealedAndSignedMessage.sealedAndSigned);
if (decryptedMsgWithPubKey.message instanceof MailboxMessage) { if (decryptedMsgWithPubKey.message instanceof MailboxMessage) {
MailboxMessage mailboxMessage = (MailboxMessage) decryptedMsgWithPubKey.message; MailboxMessage mailboxMessage = (MailboxMessage) decryptedMsgWithPubKey.message;
@ -439,7 +458,8 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) { MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) {
Log.traceCall(); Log.traceCall();
checkNotNull(peerAddress, "PeerAddress must not be null (sendEncryptedMailboxMessage)"); checkNotNull(peerAddress, "PeerAddress must not be null (sendEncryptedMailboxMessage)");
checkArgument(!keyRing.getPubKeyRing().equals(peersPubKeyRing), "We got own keyring instead of that from peer"); checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
checkArgument(!optionalKeyRing.get().getPubKeyRing().equals(peersPubKeyRing), "We got own keyring instead of that from peer");
checkAuthentication(); checkAuthentication();
if (authenticatedPeerAddresses.contains(peerAddress)) { if (authenticatedPeerAddresses.contains(peerAddress)) {
@ -458,10 +478,11 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
private void trySendEncryptedMailboxMessage(Address peerAddress, PubKeyRing peersPubKeyRing, private void trySendEncryptedMailboxMessage(Address peerAddress, PubKeyRing peersPubKeyRing,
MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) { MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) {
Log.traceCall(); Log.traceCall();
if (encryptionService != null) { checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
checkArgument(optionalEncryptionService.isPresent(), "EncryptionService not set. Seems that is called on a seed node which must not happen.");
try { try {
SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage( SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(
encryptionService.encryptAndSign(peersPubKeyRing, message), peerAddress.getAddressPrefixHash()); optionalEncryptionService.get().encryptAndSign(peersPubKeyRing, message), peerAddress.getAddressPrefixHash());
SettableFuture<Connection> future = networkNode.sendMessage(peerAddress, sealedAndSignedMessage); SettableFuture<Connection> future = networkNode.sendMessage(peerAddress, sealedAndSignedMessage);
Futures.addCallback(future, new FutureCallback<Connection>() { Futures.addCallback(future, new FutureCallback<Connection>() {
@Override @Override
@ -478,7 +499,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
log.trace("create MailboxEntry with peerAddress " + peerAddress); log.trace("create MailboxEntry with peerAddress " + peerAddress);
PublicKey receiverStoragePublicKey = peersPubKeyRing.getSignaturePubKey(); PublicKey receiverStoragePublicKey = peersPubKeyRing.getSignaturePubKey();
addMailboxData(new ExpirableMailboxPayload(sealedAndSignedMessage, addMailboxData(new ExpirableMailboxPayload(sealedAndSignedMessage,
keyRing.getSignatureKeyPair().getPublic(), optionalKeyRing.get().getSignatureKeyPair().getPublic(),
receiverStoragePublicKey), receiverStoragePublicKey),
receiverStoragePublicKey); receiverStoragePublicKey);
sendMailboxMessageListener.onStoredInMailbox(); sendMailboxMessageListener.onStoredInMailbox();
@ -490,7 +511,52 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
sendMailboxMessageListener.onFault(); sendMailboxMessageListener.onFault();
} }
} }
private void addMailboxData(ExpirableMailboxPayload expirableMailboxPayload, PublicKey receiversPublicKey) {
Log.traceCall();
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
checkAuthentication();
try {
ProtectedMailboxData protectedMailboxData = dataStorage.getMailboxDataWithSignedSeqNr(
expirableMailboxPayload,
optionalKeyRing.get().getSignatureKeyPair(),
receiversPublicKey);
dataStorage.add(protectedMailboxData, networkNode.getAddress());
} catch (CryptoException e) {
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
} }
}
public void removeEntryFromMailbox(DecryptedMsgWithPubKey decryptedMsgWithPubKey) {
Log.traceCall();
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
checkAuthentication();
if (mailboxMap.containsKey(decryptedMsgWithPubKey)) {
ProtectedMailboxData mailboxData = mailboxMap.get(decryptedMsgWithPubKey);
if (mailboxData != null && mailboxData.expirablePayload instanceof ExpirableMailboxPayload) {
ExpirableMailboxPayload expirableMailboxPayload = (ExpirableMailboxPayload) mailboxData.expirablePayload;
PublicKey receiversPubKey = mailboxData.receiversPubKey;
checkArgument(receiversPubKey.equals(optionalKeyRing.get().getSignatureKeyPair().getPublic()),
"receiversPubKey is not matching with our key. That must not happen.");
try {
ProtectedMailboxData protectedMailboxData = dataStorage.getMailboxDataWithSignedSeqNr(
expirableMailboxPayload,
optionalKeyRing.get().getSignatureKeyPair(),
receiversPubKey);
dataStorage.removeMailboxData(protectedMailboxData, networkNode.getAddress());
} catch (CryptoException e) {
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
}
mailboxMap.remove(decryptedMsgWithPubKey);
log.trace("Removed successfully decryptedMsgWithPubKey.");
}
} else {
log.warn("decryptedMsgWithPubKey not found in mailboxMap. That should never happen." +
"\ndecryptedMsgWithPubKey={}\nmailboxMap={}", decryptedMsgWithPubKey, mailboxMap);
}
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Data storage // Data storage
@ -508,10 +574,10 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
private boolean doAddData(ExpirablePayload expirablePayload, boolean rePublish) { private boolean doAddData(ExpirablePayload expirablePayload, boolean rePublish) {
Log.traceCall(); Log.traceCall();
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
checkAuthentication(); checkAuthentication();
try { try {
ProtectedData protectedData = dataStorage.getDataWithSignedSeqNr(expirablePayload, keyRing.getSignatureKeyPair()); ProtectedData protectedData = dataStorage.getDataWithSignedSeqNr(expirablePayload, optionalKeyRing.get().getSignatureKeyPair());
if (rePublish) if (rePublish)
return dataStorage.rePublish(protectedData, networkNode.getAddress()); return dataStorage.rePublish(protectedData, networkNode.getAddress());
else else
@ -522,27 +588,12 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
} }
} }
private void addMailboxData(ExpirableMailboxPayload expirableMailboxPayload, PublicKey receiversPublicKey) {
Log.traceCall();
checkAuthentication();
try {
ProtectedMailboxData protectedMailboxData = dataStorage.getMailboxDataWithSignedSeqNr(
expirableMailboxPayload,
keyRing.getSignatureKeyPair(),
receiversPublicKey);
dataStorage.add(protectedMailboxData, networkNode.getAddress());
} catch (CryptoException e) {
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
}
}
public boolean removeData(ExpirablePayload expirablePayload) { public boolean removeData(ExpirablePayload expirablePayload) {
Log.traceCall(); Log.traceCall();
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
checkAuthentication(); checkAuthentication();
try { try {
ProtectedData protectedData = dataStorage.getDataWithSignedSeqNr(expirablePayload, keyRing.getSignatureKeyPair()); ProtectedData protectedData = dataStorage.getDataWithSignedSeqNr(expirablePayload, optionalKeyRing.get().getSignatureKeyPair());
return dataStorage.remove(protectedData, networkNode.getAddress()); return dataStorage.remove(protectedData, networkNode.getAddress());
} catch (CryptoException e) { } catch (CryptoException e) {
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen."); log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
@ -550,40 +601,6 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
} }
} }
public void removeEntryFromMailbox(DecryptedMsgWithPubKey decryptedMsgWithPubKey) {
Log.traceCall();
checkAuthentication();
if (mailboxMap.containsKey(decryptedMsgWithPubKey)) {
ProtectedMailboxData mailboxData = mailboxMap.get(decryptedMsgWithPubKey);
if (mailboxData != null && mailboxData.expirablePayload instanceof ExpirableMailboxPayload) {
ExpirableMailboxPayload expirableMailboxPayload = (ExpirableMailboxPayload) mailboxData.expirablePayload;
PublicKey receiversPubKey = mailboxData.receiversPubKey;
checkArgument(receiversPubKey.equals(keyRing.getSignatureKeyPair().getPublic()),
"receiversPubKey is not matching with our key. That must not happen.");
try {
ProtectedMailboxData protectedMailboxData = dataStorage.getMailboxDataWithSignedSeqNr(
expirableMailboxPayload,
keyRing.getSignatureKeyPair(),
receiversPubKey);
dataStorage.removeMailboxData(protectedMailboxData, networkNode.getAddress());
} catch (CryptoException e) {
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
}
mailboxMap.remove(decryptedMsgWithPubKey);
log.trace("Removed successfully decryptedMsgWithPubKey.");
}
} else {
log.warn("decryptedMsgWithPubKey not found in mailboxMap. That should never happen." +
"\ndecryptedMsgWithPubKey={}\nmailboxMap={}", decryptedMsgWithPubKey, mailboxMap);
}
}
public Map<ByteArray, ProtectedData> getDataMap() {
return dataStorage.getMap();
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Listeners // Listeners
@ -646,15 +663,15 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
return numAuthenticatedPeers; return numAuthenticatedPeers;
} }
public Map<ByteArray, ProtectedData> getDataMap() {
return dataStorage.getMap();
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private HashSet<ProtectedData> getDataSet() {
return new HashSet<>(getDataMap().values());
}
private boolean verifyAddressPrefixHash(SealedAndSignedMessage sealedAndSignedMessage) { private boolean verifyAddressPrefixHash(SealedAndSignedMessage sealedAndSignedMessage) {
if (myOnionAddress != null) { if (myOnionAddress != null) {
byte[] blurredAddressHash = myOnionAddress.getAddressPrefixHash(); byte[] blurredAddressHash = myOnionAddress.getAddressPrefixHash();

View file

@ -120,8 +120,6 @@ public class Connection implements MessageListener {
Log.traceCall(); Log.traceCall();
this.peerAddress = peerAddress; this.peerAddress = peerAddress;
isAuthenticated = true; isAuthenticated = true;
if (!stopped)
connectionListener.onPeerAddressAuthenticated(peerAddress, connection);
} }
public void setConnectionPriority(ConnectionPriority connectionPriority) { public void setConnectionPriority(ConnectionPriority connectionPriority) {

View file

@ -1,8 +1,6 @@
package io.bitsquare.p2p.network; package io.bitsquare.p2p.network;
import io.bitsquare.p2p.Address;
public interface ConnectionListener { public interface ConnectionListener {
enum Reason { enum Reason {
SOCKET_CLOSED, SOCKET_CLOSED,
@ -15,8 +13,6 @@ public interface ConnectionListener {
void onConnection(Connection connection); void onConnection(Connection connection);
void onPeerAddressAuthenticated(Address peerAddress, Connection connection);
void onDisconnect(Reason reason, Connection connection); void onDisconnect(Reason reason, Connection connection);
void onError(Throwable throwable); void onError(Throwable throwable);

View file

@ -230,14 +230,6 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener
connectionListeners.stream().forEach(e -> e.onConnection(connection)); connectionListeners.stream().forEach(e -> e.onConnection(connection));
} }
@Override
public void onPeerAddressAuthenticated(Address peerAddress, Connection connection) {
Log.traceCall();
log.trace("onAuthenticationComplete peerAddress/connection: " + peerAddress + " / " + connection);
connectionListeners.stream().forEach(e -> e.onPeerAddressAuthenticated(peerAddress, connection));
}
@Override @Override
public void onDisconnect(Reason reason, Connection connection) { public void onDisconnect(Reason reason, Connection connection) {
Log.traceCall(); Log.traceCall();
@ -320,12 +312,6 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener
NetworkNode.this.onConnection(connection); NetworkNode.this.onConnection(connection);
} }
@Override
public void onPeerAddressAuthenticated(Address peerAddress, Connection connection) {
Log.traceCall();
NetworkNode.this.onPeerAddressAuthenticated(peerAddress, connection);
}
@Override @Override
public void onDisconnect(Reason reason, Connection connection) { public void onDisconnect(Reason reason, Connection connection) {
Log.traceCall(); Log.traceCall();

View file

@ -0,0 +1,8 @@
package io.bitsquare.p2p.peers;
import io.bitsquare.p2p.Address;
import io.bitsquare.p2p.network.Connection;
public interface AuthenticationListener {
void onPeerAddressAuthenticated(Address peerAddress, Connection connection);
}

View file

@ -18,6 +18,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.*; import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -40,19 +41,18 @@ public class PeerGroup implements MessageListener, ConnectionListener {
MAX_CONNECTIONS_LOW_PRIO = maxConnectionsLowPrio; MAX_CONNECTIONS_LOW_PRIO = maxConnectionsLowPrio;
} }
private static final int PING_AFTER_CONNECTION_INACTIVITY = 30 * 1000; private static final int INACTIVITY_PERIOD_BEFORE_PING = 30 * 1000;
private static final int MAX_REPORTED_PEERS = 1000; private static final int MAX_REPORTED_PEERS = 1000;
private final NetworkNode networkNode; private final NetworkNode networkNode;
private Set<Address> seedNodeAddresses; private final CopyOnWriteArraySet<AuthenticationListener> authenticationListeners = new CopyOnWriteArraySet<>();
private final Map<Address, Peer> authenticatedPeers = new HashMap<>(); private final Map<Address, Peer> authenticatedPeers = new HashMap<>();
private final Set<ReportedPeer> reportedPeers = new HashSet<>(); private final Set<ReportedPeer> reportedPeers = new HashSet<>();
private final Map<Address, AuthenticationHandshake> authenticationHandshakes = new HashMap<>(); private final Map<Address, AuthenticationHandshake> authenticationHandshakes = new HashMap<>();
private Timer sendPingTimer;
private Timer getPeersTimer;
private Timer sendPingTimer = new Timer(); private Set<Address> seedNodeAddresses;
private Timer getPeersTimer = new Timer();
private boolean shutDownInProgress; private boolean shutDownInProgress;
@ -72,10 +72,29 @@ public class PeerGroup implements MessageListener, ConnectionListener {
startGetPeersTimer(); startGetPeersTimer();
} }
public void setSeedNodeAddresses(Set<Address> seedNodeAddresses) { public void addAuthenticationListener(AuthenticationListener listener) {
this.seedNodeAddresses = seedNodeAddresses; authenticationListeners.add(listener);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// ConnectionListener implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onConnection(Connection connection) {
}
@Override
public void onDisconnect(Reason reason, Connection connection) {
log.debug("onDisconnect connection=" + connection + " / reason=" + reason);
removePeer(connection.getPeerAddress());
}
@Override
public void onError(Throwable throwable) {
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// MessageListener implementation // MessageListener implementation
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -89,33 +108,14 @@ public class PeerGroup implements MessageListener, ConnectionListener {
} }
///////////////////////////////////////////////////////////////////////////////////////////
// ConnectionListener implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onConnection(Connection connection) {
}
@Override
public void onPeerAddressAuthenticated(Address peerAddress, Connection connection) {
}
@Override
public void onDisconnect(Reason reason, Connection connection) {
log.debug("onDisconnect connection=" + connection + " / reason=" + reason);
removePeer(connection.getPeerAddress());
}
@Override
public void onError(Throwable throwable) {
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// API // API
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void setSeedNodeAddresses(Set<Address> seedNodeAddresses) {
this.seedNodeAddresses = seedNodeAddresses;
}
public void broadcast(DataBroadcastMessage message, @Nullable Address sender) { public void broadcast(DataBroadcastMessage message, @Nullable Address sender) {
Log.traceCall("Sender " + sender + ". Message " + message.toString()); Log.traceCall("Sender " + sender + ". Message " + message.toString());
if (authenticatedPeers.values().size() > 0) { if (authenticatedPeers.values().size() > 0) {
@ -442,6 +442,7 @@ public class PeerGroup implements MessageListener, ConnectionListener {
addAuthenticatedPeer(new Peer(connection)); addAuthenticatedPeer(new Peer(connection));
connection.setAuthenticated(peerAddress, connection); connection.setAuthenticated(peerAddress, connection);
authenticationListeners.stream().forEach(e -> e.onPeerAddressAuthenticated(peerAddress, connection));
} }
private void addAuthenticatedPeer(Peer peer) { private void addAuthenticatedPeer(Peer peer) {
@ -455,6 +456,7 @@ public class PeerGroup implements MessageListener, ConnectionListener {
printAuthenticatedPeers(); printAuthenticatedPeers();
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Maintenance // Maintenance
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -542,7 +544,7 @@ public class PeerGroup implements MessageListener, ConnectionListener {
if (!connectedPeersList.isEmpty()) { if (!connectedPeersList.isEmpty()) {
Log.traceCall(); Log.traceCall();
connectedPeersList.stream() connectedPeersList.stream()
.filter(e -> (new Date().getTime() - e.connection.getLastActivityDate().getTime()) > PING_AFTER_CONNECTION_INACTIVITY) .filter(e -> (new Date().getTime() - e.connection.getLastActivityDate().getTime()) > INACTIVITY_PERIOD_BEFORE_PING)
.forEach(e -> UserThread.runAfterRandomDelay(() -> { .forEach(e -> UserThread.runAfterRandomDelay(() -> {
SettableFuture<Connection> future = networkNode.sendMessage(e.connection, new PingMessage(e.getPingNonce())); SettableFuture<Connection> future = networkNode.sendMessage(e.connection, new PingMessage(e.getPingNonce()));
Futures.addCallback(future, new FutureCallback<Connection>() { Futures.addCallback(future, new FutureCallback<Connection>() {

View file

@ -8,7 +8,6 @@ import io.bitsquare.common.UserThread;
import io.bitsquare.p2p.Address; import io.bitsquare.p2p.Address;
import io.bitsquare.p2p.Message; import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.network.Connection; import io.bitsquare.p2p.network.Connection;
import io.bitsquare.p2p.network.ConnectionListener;
import io.bitsquare.p2p.network.MessageListener; import io.bitsquare.p2p.network.MessageListener;
import io.bitsquare.p2p.network.NetworkNode; import io.bitsquare.p2p.network.NetworkNode;
import io.bitsquare.p2p.storage.P2PDataStorage; import io.bitsquare.p2p.storage.P2PDataStorage;
@ -25,7 +24,7 @@ import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
public class RequestDataManager implements MessageListener, ConnectionListener { public class RequestDataManager implements MessageListener, AuthenticationListener {
private static final Logger log = LoggerFactory.getLogger(RequestDataManager.class); private static final Logger log = LoggerFactory.getLogger(RequestDataManager.class);
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -56,7 +55,6 @@ public class RequestDataManager implements MessageListener, ConnectionListener {
this.listener = listener; this.listener = listener;
networkNode.addMessageListener(this); networkNode.addMessageListener(this);
networkNode.addConnectionListener(this);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -129,13 +127,11 @@ public class RequestDataManager implements MessageListener, ConnectionListener {
listener.onDataReceived(connectedSeedNodeAddress); listener.onDataReceived(connectedSeedNodeAddress);
} }
} }
///////////////////////////////////////////////////////////////////////////////////////////
// ConnectionListener implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onConnection(Connection connection) { ///////////////////////////////////////////////////////////////////////////////////////////
} // AuthenticationListener implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
public void onPeerAddressAuthenticated(Address peerAddress, Connection connection) { public void onPeerAddressAuthenticated(Address peerAddress, Connection connection) {
@ -143,13 +139,6 @@ public class RequestDataManager implements MessageListener, ConnectionListener {
requestDataFromAuthenticatedSeedNode(peerAddress, connection); requestDataFromAuthenticatedSeedNode(peerAddress, connection);
} }
@Override
public void onDisconnect(Reason reason, Connection connection) {
}
@Override
public void onError(Throwable throwable) {
}
// 5. Step after authentication to first seed node we request again the data // 5. Step after authentication to first seed node we request again the data
private void requestDataFromAuthenticatedSeedNode(Address peerAddress, Connection connection) { private void requestDataFromAuthenticatedSeedNode(Address peerAddress, Connection connection) {