diff --git a/core/src/main/java/com/google/bitcoin/core/NetworkConnection.java b/core/src/main/java/com/google/bitcoin/core/NetworkConnection.java index 05c15c3c6..eb7c70790 100644 --- a/core/src/main/java/com/google/bitcoin/core/NetworkConnection.java +++ b/core/src/main/java/com/google/bitcoin/core/NetworkConnection.java @@ -32,6 +32,15 @@ import java.io.IOException; */ public interface NetworkConnection { /** + * Connect to the remote peer. + * + * @param peerAddress the address of the remote peer + * @param connectTimeoutMsec timeout in milliseconds + */ + public void connect(PeerAddress peerAddress, int connectTimeoutMsec) + throws IOException, ProtocolException; + + /** * Sends a "ping" message to the remote node. The protocol doesn't presently use this feature much. * * @throws IOException diff --git a/core/src/main/java/com/google/bitcoin/core/Peer.java b/core/src/main/java/com/google/bitcoin/core/Peer.java index 544d7fc00..6c97f19ab 100644 --- a/core/src/main/java/com/google/bitcoin/core/Peer.java +++ b/core/src/main/java/com/google/bitcoin/core/Peer.java @@ -154,7 +154,8 @@ public class Peer { */ public synchronized void connect() throws PeerException { try { - conn = new TCPNetworkConnection(address, params, CONNECT_TIMEOUT_MSEC, false, versionMessage); + conn = new TCPNetworkConnection(params, false, versionMessage); + conn.connect(address, CONNECT_TIMEOUT_MSEC); } catch (IOException ex) { throw new PeerException(ex); } catch (ProtocolException ex) { diff --git a/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java b/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java index f5676f4b5..a88b222de 100644 --- a/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java +++ b/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java @@ -40,16 +40,18 @@ public class TCPNetworkConnection implements NetworkConnection { private static final Logger log = LoggerFactory.getLogger(TCPNetworkConnection.class); private final Socket socket; - private final OutputStream out; - private final InputStream in; + private OutputStream out; + private InputStream in; // The IP address to which we are connecting. - private final InetAddress remoteIp; + private InetAddress remoteIp; private final NetworkParameters params; - private final VersionMessage versionMessage; + private VersionMessage versionMessage; // Given to the BitcoinSerializer to de-duplicate messages. private static final LinkedHashMap dedupeList = BitcoinSerializer.createDedupeList(); private BitcoinSerializer serializer = null; + + private VersionMessage myVersionMessage; private static final Date checksummingProtocolChangeDate = new Date(1329696000000L); /** @@ -65,30 +67,35 @@ public class TCPNetworkConnection implements NetworkConnection { * @throws IOException if there is a network related failure. * @throws ProtocolException if the version negotiation failed. */ - public TCPNetworkConnection(PeerAddress peerAddress, NetworkParameters params, - int connectTimeoutMsec, boolean dedupe, VersionMessage ver) + public TCPNetworkConnection(NetworkParameters params, boolean dedupe, VersionMessage ver) throws IOException, ProtocolException { this.params = params; - this.remoteIp = peerAddress.getAddr(); + this.myVersionMessage = ver; - int port = (peerAddress.getPort() > 0) ? peerAddress.getPort() : params.port; + socket = new Socket(); + + // So pre-Feb 2012, update checkumming property after version is read. + this.serializer = new BitcoinSerializer(this.params, false, dedupe ? dedupeList : null); + this.serializer.setUseChecksumming(Utils.now().after(checksummingProtocolChangeDate)); + } + + public void connect(PeerAddress peerAddress, int connectTimeoutMsec) + throws IOException, ProtocolException { + remoteIp = peerAddress.getAddr(); + int port = (peerAddress.getPort() > 0) ? peerAddress.getPort() : this.params.port; InetSocketAddress address = new InetSocketAddress(remoteIp, port); - socket = new Socket(); + socket.connect(address, connectTimeoutMsec); out = socket.getOutputStream(); in = socket.getInputStream(); // The version message does not use checksumming, until Feb 2012 when it magically does. - // So pre-Feb 2012, update checkumming property after version is read. - this.serializer = new BitcoinSerializer(params, false, dedupe ? dedupeList : null); - this.serializer.setUseChecksumming(Utils.now().after(checksummingProtocolChangeDate)); - // Announce ourselves. This has to come first to connect to clients beyond v0.30.20.2 which wait to hear // from us until they send their version message back. - log.info("Announcing ourselves as: {}", ver.subVer); - writeMessage(ver); + log.info("Announcing ourselves as: {}", myVersionMessage.subVer); + writeMessage(myVersionMessage); // When connecting, the remote peer sends us a version message with various bits of // useful data in it. We need to know the peer protocol version before we can talk to it. Message m = readMessage(); @@ -140,15 +147,15 @@ public class TCPNetworkConnection implements NetworkConnection { * @throws IOException if there is a network related failure. * @throws ProtocolException if the version negotiation failed. */ - public TCPNetworkConnection(PeerAddress peerAddress, NetworkParameters params, - int bestHeight, int connectTimeoutMsec, boolean dedupe) + public TCPNetworkConnection(NetworkParameters params, + int bestHeight, boolean dedupe) throws IOException, ProtocolException { - this(peerAddress, params, connectTimeoutMsec, dedupe, new VersionMessage(params, bestHeight)); + this(params, dedupe, new VersionMessage(params, bestHeight)); } - public TCPNetworkConnection(InetAddress inetAddress, NetworkParameters params, int bestHeight, int connectTimeout) + public TCPNetworkConnection(NetworkParameters params, int bestHeight) throws IOException, ProtocolException { - this(new PeerAddress(inetAddress), params, bestHeight, connectTimeout, true); + this(params, bestHeight, true); } diff --git a/core/src/test/java/com/google/bitcoin/core/MockNetworkConnection.java b/core/src/test/java/com/google/bitcoin/core/MockNetworkConnection.java index 3465871f8..afaf06872 100644 --- a/core/src/test/java/com/google/bitcoin/core/MockNetworkConnection.java +++ b/core/src/test/java/com/google/bitcoin/core/MockNetworkConnection.java @@ -37,13 +37,13 @@ public class MockNetworkConnection implements NetworkConnection { private PeerAddress peerAddress; public MockNetworkConnection() { + } + + + public void connect(PeerAddress peerAddress, int connectTimeoutMsec) { inboundMessageQ = new ArrayBlockingQueue(10); outboundMessageQ = new ArrayBlockingQueue(10); - try { - peerAddress = new PeerAddress(InetAddress.getLocalHost(), fakePort++); - } catch (UnknownHostException e) { - throw new RuntimeException(e); // Cannot happen. - } + this.peerAddress = peerAddress; } public void ping() throws IOException { diff --git a/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java b/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java index c1d6f9a51..de34db3bc 100644 --- a/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java +++ b/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java @@ -21,6 +21,8 @@ import com.google.bitcoin.utils.BriefLogFormatter; import org.easymock.IMocksControl; import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; import static org.easymock.EasyMock.createStrictControl; @@ -35,6 +37,7 @@ public class TestWithNetworkConnections { protected Wallet wallet; protected ECKey key; protected Address address; + private static int fakePort; public void setUp() throws Exception { BriefLogFormatter.init(); @@ -52,7 +55,13 @@ public class TestWithNetworkConnections { } protected MockNetworkConnection createMockNetworkConnection() { - return new MockNetworkConnection(); + MockNetworkConnection conn = new MockNetworkConnection(); + try { + conn.connect(new PeerAddress(InetAddress.getLocalHost(), fakePort++), 0); + } catch (UnknownHostException e) { + throw new RuntimeException(e); // Cannot happen + } + return conn; } protected void runPeer(Peer peer, MockNetworkConnection connection) throws IOException, PeerException { @@ -65,7 +74,7 @@ public class TestWithNetworkConnections { } } - protected void runPeerAsync(final Peer peer, MockNetworkConnection connection) throws IOException, PeerException { + protected void runPeerAsync(final Peer peer, MockNetworkConnection connection) { new Thread("Test Peer Thread") { @Override public void run() { diff --git a/examples/src/main/java/com/google/bitcoin/examples/PrintPeers.java b/examples/src/main/java/com/google/bitcoin/examples/PrintPeers.java index 91b204d7e..b8c716810 100644 --- a/examples/src/main/java/com/google/bitcoin/examples/PrintPeers.java +++ b/examples/src/main/java/com/google/bitcoin/examples/PrintPeers.java @@ -18,6 +18,7 @@ package com.google.bitcoin.examples; import com.google.bitcoin.core.NetworkConnection; import com.google.bitcoin.core.NetworkParameters; +import com.google.bitcoin.core.PeerAddress; import com.google.bitcoin.core.TCPNetworkConnection; import com.google.bitcoin.discovery.DnsDiscovery; import com.google.bitcoin.discovery.IrcDiscovery; @@ -94,8 +95,9 @@ public class PrintPeers { pool.submit(new Runnable() { public void run() { try { - NetworkConnection conn = new TCPNetworkConnection(addr, - NetworkParameters.prodNet(), 0, 1000); + NetworkConnection conn = + new TCPNetworkConnection(NetworkParameters.prodNet(), 0); + conn.connect(new PeerAddress(addr), 1000); synchronized (lock) { long nodeHeight = conn.getVersionMessage().bestHeight; long diff = bestHeight[0] - nodeHeight;