diff --git a/core/src/main/java/com/google/bitcoin/net/BlockingClient.java b/core/src/main/java/com/google/bitcoin/net/BlockingClient.java
index e2ecf9d6..ee4c90ae 100644
--- a/core/src/main/java/com/google/bitcoin/net/BlockingClient.java
+++ b/core/src/main/java/com/google/bitcoin/net/BlockingClient.java
@@ -19,8 +19,10 @@ package com.google.bitcoin.net;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
+import javax.net.SocketFactory;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
@@ -42,7 +44,7 @@ public class BlockingClient implements MessageWriteTarget {
private static final int BUFFER_SIZE_UPPER_BOUND = 65536;
private final ByteBuffer dbuf;
- private final Socket socket;
+ private Socket socket;
private volatile boolean vCloseRequested = false;
/**
@@ -53,17 +55,17 @@ public class BlockingClient implements MessageWriteTarget {
*
* @param connectTimeoutMillis The connect timeout set on the connection (in milliseconds). 0 is interpreted as no
* timeout.
+ * @param socketFactory An object that creates {@link Socket} objects on demand, which may be customised to control
+ * how this client connects to the internet. If not sure, use SocketFactory.getDefault()
* @param clientSet A set which this object will add itself to after initialization, and then remove itself from
- * when the connection dies. Note that this set must be thread-safe.
*/
public BlockingClient(final SocketAddress serverAddress, final StreamParser parser,
- final int connectTimeoutMillis, @Nullable final Set clientSet) throws IOException {
+ final int connectTimeoutMillis, final SocketFactory socketFactory, @Nullable final Set clientSet) throws IOException {
// Try to fit at least one message in the network buffer, but place an upper and lower limit on its size to make
// sure it doesnt get too large or have to call read too often.
dbuf = ByteBuffer.allocateDirect(Math.min(Math.max(parser.getMaxMessageSize(), BUFFER_SIZE_LOWER_BOUND), BUFFER_SIZE_UPPER_BOUND));
parser.setWriteTarget(this);
- socket = new Socket();
-
+ socket = socketFactory.createSocket();
Thread t = new Thread() {
@Override
public void run() {
@@ -129,7 +131,9 @@ public class BlockingClient implements MessageWriteTarget {
@Override
public synchronized void writeBytes(byte[] message) throws IOException {
try {
- socket.getOutputStream().write(message);
+ OutputStream stream = socket.getOutputStream();
+ stream.write(message);
+ stream.flush();
} catch (IOException e) {
log.error("Error writing message to connection, closing connection", e);
closeConnection();
diff --git a/core/src/main/java/com/google/bitcoin/net/BlockingClientManager.java b/core/src/main/java/com/google/bitcoin/net/BlockingClientManager.java
index 7fe45bc9..46efb170 100644
--- a/core/src/main/java/com/google/bitcoin/net/BlockingClientManager.java
+++ b/core/src/main/java/com/google/bitcoin/net/BlockingClientManager.java
@@ -18,6 +18,7 @@ package com.google.bitcoin.net;
import com.google.common.util.concurrent.AbstractIdleService;
+import javax.net.SocketFactory;
import java.io.IOException;
import java.net.SocketAddress;
import java.util.Collections;
@@ -25,6 +26,8 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* A thin wrapper around a set of {@link BlockingClient}s.
*
@@ -33,18 +36,39 @@ import java.util.Set;
* some other network settings that cannot be set using NIO.
*/
public class BlockingClientManager extends AbstractIdleService implements ClientConnectionManager {
+ private final SocketFactory socketFactory;
private final Set clients = Collections.synchronizedSet(new HashSet());
+
+ private int connectTimeoutMillis = 1000;
+
+ public BlockingClientManager() {
+ socketFactory = SocketFactory.getDefault();
+ }
+
+ /**
+ * Creates a blocking client manager that will obtain sockets from the given factory. Useful for customising how
+ * bitcoinj connects to the P2P network.
+ */
+ public BlockingClientManager(SocketFactory socketFactory) {
+ this.socketFactory = checkNotNull(socketFactory);
+ }
+
@Override
public void openConnection(SocketAddress serverAddress, StreamParser parser) {
if (!isRunning())
throw new IllegalStateException();
try {
- new BlockingClient(serverAddress, parser, 1000, clients);
+ new BlockingClient(serverAddress, parser, connectTimeoutMillis, socketFactory, clients);
} catch (IOException e) {
throw new RuntimeException(e); // This should only happen if we are, eg, out of system resources
}
}
+ /** Sets the number of milliseconds to wait before giving up on a connect attempt */
+ public void setConnectTimeoutMillis(int connectTimeoutMillis) {
+ this.connectTimeoutMillis = connectTimeoutMillis;
+ }
+
@Override
protected void startUp() throws Exception { }
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 ec85853e..1b67479f 100644
--- a/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java
+++ b/core/src/test/java/com/google/bitcoin/core/TestWithNetworkConnections.java
@@ -24,6 +24,8 @@ import com.google.bitcoin.utils.BriefLogFormatter;
import com.google.bitcoin.utils.Threading;
import com.google.common.util.concurrent.SettableFuture;
+import javax.annotation.Nullable;
+import javax.net.SocketFactory;
import java.io.IOException;
import java.math.BigInteger;
import java.net.InetAddress;
@@ -32,7 +34,6 @@ import java.net.SocketAddress;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
-import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkArgument;
import static org.junit.Assert.assertTrue;
@@ -152,7 +153,7 @@ public class TestWithNetworkConnections {
else if (clientType == ClientType.NIO_CLIENT)
new NioClient(new InetSocketAddress("127.0.0.1", 2000), peer, 100);
else if (clientType == ClientType.BLOCKING_CLIENT)
- new BlockingClient(new InetSocketAddress("127.0.0.1", 2000), peer, 100, null);
+ new BlockingClient(new InetSocketAddress("127.0.0.1", 2000), peer, 100, SocketFactory.getDefault(), null);
else
throw new RuntimeException();
// Claim we are connected to a different IP that what we really are, so tx confidence broadcastBy sets work
diff --git a/core/src/test/java/com/google/bitcoin/net/NetworkAbstractionTests.java b/core/src/test/java/com/google/bitcoin/net/NetworkAbstractionTests.java
index 37448244..dab55eec 100644
--- a/core/src/test/java/com/google/bitcoin/net/NetworkAbstractionTests.java
+++ b/core/src/test/java/com/google/bitcoin/net/NetworkAbstractionTests.java
@@ -16,13 +16,6 @@
package com.google.bitcoin.net;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.concurrent.atomic.AtomicBoolean;
-
import com.google.bitcoin.core.Utils;
import com.google.common.util.concurrent.SettableFuture;
import com.google.protobuf.ByteString;
@@ -33,8 +26,17 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import javax.net.SocketFactory;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import static com.google.common.base.Preconditions.checkState;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
@RunWith(value = Parameterized.class)
public class NetworkAbstractionTests {
@@ -68,7 +70,7 @@ public class NetworkAbstractionTests {
} else if (clientType == 2)
return new NioClient(addr, parser, 100);
else if (clientType == 3)
- return new BlockingClient(addr, parser, 100, null);
+ return new BlockingClient(addr, parser, 100, SocketFactory.getDefault(), null);
else
throw new RuntimeException();
}