diff --git a/core/src/main/java/com/google/bitcoin/discovery/DnsDiscovery.java b/core/src/main/java/com/google/bitcoin/discovery/DnsDiscovery.java index 32e66740..c55b48cf 100644 --- a/core/src/main/java/com/google/bitcoin/discovery/DnsDiscovery.java +++ b/core/src/main/java/com/google/bitcoin/discovery/DnsDiscovery.java @@ -17,17 +17,13 @@ package com.google.bitcoin.discovery; import com.google.bitcoin.core.NetworkParameters; -import com.google.common.collect.Sets; +import com.google.common.collect.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Set; +import java.util.*; import java.util.concurrent.*; /** @@ -71,50 +67,46 @@ public class DnsDiscovery implements PeerDiscovery { } public InetSocketAddress[] getPeers(long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException { - final BlockingQueue queue = new LinkedBlockingQueue(); - - ArrayList seeds = new ArrayList(Arrays.asList(hostNames)); // Java doesn't have an async DNS API so we have to do all lookups in a thread pool, as sometimes seeds go // hard down and it takes ages to give up and move on. - ExecutorService pool = Executors.newFixedThreadPool(seeds.size()); - for (final String seed : seeds) { - pool.submit(new Runnable() { - public void run() { - try { - InetAddress[] addrs = InetAddress.getAllByName(seed); - for (InetAddress addr : addrs) queue.put(new InetSocketAddress(addr, netParams.port)); - } catch (UnknownHostException e) { - log.warn("Unable to resolve {}", seed); - } catch (InterruptedException e) { - // Silently go away. + ExecutorService threadPool = Executors.newFixedThreadPool(hostNames.length); + try { + List> tasks = Lists.newArrayList(); + for (final String seed : hostNames) + tasks.add(new Callable() { + public InetAddress[] call() throws Exception { + return InetAddress.getAllByName(seed); } + }); + final List> futures = threadPool.invokeAll(tasks, timeoutValue, timeoutUnit); + ArrayList addrs = Lists.newArrayList(); + for (int i = 0; i < futures.size(); i++) { + Future future = futures.get(i); + if (future.isCancelled()) { + log.warn("{} timed out", hostNames[i]); + continue; // Timed out. } - }); - } - // The queue will fill up with resolutions. Let's wait until we got at least 30 or we run out of time. - final long timeout = timeoutUnit.toMillis(timeoutValue); - long start = System.currentTimeMillis(); - Set addrs = Sets.newHashSet(); - while (addrs.size() < 30) { - try { - long pollTime = timeout - (System.currentTimeMillis() - start); - if (pollTime < 0) break; - InetSocketAddress a = queue.poll(pollTime, TimeUnit.MILLISECONDS); - if (a == null) { - break; + final InetAddress[] inetAddresses; + try { + inetAddresses = future.get(); + } catch (ExecutionException e) { + log.error("Failed to look up DNS seeds from {}: {}", hostNames[i], e.getMessage()); + continue; + } + for (InetAddress addr : inetAddresses) { + addrs.add(new InetSocketAddress(addr, netParams.port)); } - addrs.add(a); - } catch (InterruptedException e) { - break; } + if (addrs.size() == 0) + throw new PeerDiscoveryException("Unable to find any peers via DNS"); + Collections.shuffle(addrs); + threadPool.shutdownNow(); + return addrs.toArray(new InetSocketAddress[addrs.size()]); + } catch (InterruptedException e) { + throw new PeerDiscoveryException(e); + } finally { + threadPool.shutdown(); } - if (addrs.size() == 0) { - throw new PeerDiscoveryException("Unable to find any peers via DNS"); - } - ArrayList shuffledAddrs = new ArrayList(addrs); - Collections.shuffle(shuffledAddrs); - pool.shutdown(); - return shuffledAddrs.toArray(new InetSocketAddress[shuffledAddrs.size()]); } /** We don't have a way to abort a DNS lookup, so this does nothing */