|
|
|
|
@ -10,6 +10,7 @@
|
|
|
|
|
import java.io.*;
|
|
|
|
|
import java.net.*;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.concurrent.*;
|
|
|
|
|
|
|
|
|
|
import net.java.sip.communicator.service.dns.*;
|
|
|
|
|
import net.java.sip.communicator.util.*;
|
|
|
|
|
@ -43,13 +44,13 @@ public class ParallelResolverImpl
|
|
|
|
|
* class and its instances for logging output.
|
|
|
|
|
*/
|
|
|
|
|
private static final Logger logger = Logger
|
|
|
|
|
.getLogger(ParallelResolverImpl.class.getName());
|
|
|
|
|
.getLogger(ParallelResolverImpl.class);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Indicates whether we are currently in a mode where all DNS queries are
|
|
|
|
|
* sent to both the primary and the backup DNS servers.
|
|
|
|
|
*/
|
|
|
|
|
private static boolean redundantMode = false;
|
|
|
|
|
private volatile static boolean redundantMode = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The currently configured number of milliseconds that we need to wait
|
|
|
|
|
@ -87,11 +88,15 @@ public class ParallelResolverImpl
|
|
|
|
|
*/
|
|
|
|
|
private ExtendedResolver backupResolver;
|
|
|
|
|
|
|
|
|
|
/** Thread pool that processes the backup queries. */
|
|
|
|
|
private ExecutorService backupQueriesPool;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a new instance of this class.
|
|
|
|
|
*/
|
|
|
|
|
ParallelResolverImpl()
|
|
|
|
|
{
|
|
|
|
|
backupQueriesPool = Executors.newCachedThreadPool();
|
|
|
|
|
DnsUtilActivator.getConfigurationService()
|
|
|
|
|
.addPropertyChangeListener(this);
|
|
|
|
|
initProperties();
|
|
|
|
|
@ -117,8 +122,8 @@ private void initProperties()
|
|
|
|
|
}
|
|
|
|
|
catch(UnknownHostException exc)
|
|
|
|
|
{
|
|
|
|
|
logger.warn("Oh! Seems like our primary DNS is down!"
|
|
|
|
|
+ "Don't panic! We'll try to fall back to "
|
|
|
|
|
logger
|
|
|
|
|
.warn("Seems like the primary DNS is down, trying fallback to "
|
|
|
|
|
+ customResolverIP);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -193,23 +198,12 @@ private void setBackupServers(InetSocketAddress[] backupServers)
|
|
|
|
|
public Message send(Message query)
|
|
|
|
|
throws IOException
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
ParallelResolution resolution = new ParallelResolution(query);
|
|
|
|
|
|
|
|
|
|
resolution.sendFirstQuery();
|
|
|
|
|
|
|
|
|
|
//make a copy of the redundant mode variable in case we are currently
|
|
|
|
|
//completed a redemption that started earlier.
|
|
|
|
|
boolean redundantModeCopy;
|
|
|
|
|
|
|
|
|
|
synchronized(redemptionLock)
|
|
|
|
|
{
|
|
|
|
|
redundantModeCopy = redundantMode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//if we are not in redundant mode we should wait a bit and see how this
|
|
|
|
|
//goes. if we get a reply we could return bravely.
|
|
|
|
|
if(!redundantModeCopy)
|
|
|
|
|
if(!redundantMode)
|
|
|
|
|
{
|
|
|
|
|
if(resolution.waitForResponse(currentDnsPatience))
|
|
|
|
|
{
|
|
|
|
|
@ -222,8 +216,10 @@ public Message send(Message query)
|
|
|
|
|
{
|
|
|
|
|
redundantMode = true;
|
|
|
|
|
redemptionStatus = currentDnsRedemption;
|
|
|
|
|
logger.info("Primary DNS seems laggy as we got no "
|
|
|
|
|
+"response for " + currentDnsPatience + "ms. "
|
|
|
|
|
logger.info("Primary DNS seems laggy: "
|
|
|
|
|
+ "no response for " + query.getQuestion().getName()
|
|
|
|
|
+ "/" + Type.string(query.getQuestion().getType())
|
|
|
|
|
+ " after " + currentDnsPatience + "ms. "
|
|
|
|
|
+ "Enabling redundant mode.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -231,7 +227,6 @@ public Message send(Message query)
|
|
|
|
|
|
|
|
|
|
//we are definitely in redundant mode now
|
|
|
|
|
resolution.sendBackupQueries();
|
|
|
|
|
|
|
|
|
|
resolution.waitForResponse(0);
|
|
|
|
|
|
|
|
|
|
//check if it is time to end redundant mode.
|
|
|
|
|
@ -270,7 +265,7 @@ public Message send(Message query)
|
|
|
|
|
*/
|
|
|
|
|
public Object sendAsync(final Message query, final ResolverListener listener)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
throw new UnsupportedOperationException("Not implemented");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -448,7 +443,7 @@ private boolean isResponseSatisfactory(Message response)
|
|
|
|
|
* our default and backup servers and returns as soon as we get one or until
|
|
|
|
|
* our default resolver fails.
|
|
|
|
|
*/
|
|
|
|
|
private class ParallelResolution extends Thread
|
|
|
|
|
private class ParallelResolution implements Runnable
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* The query that we have sent to the default and backup DNS servers.
|
|
|
|
|
@ -459,7 +454,7 @@ private class ParallelResolution extends Thread
|
|
|
|
|
* The field where we would store the first incoming response to our
|
|
|
|
|
* query.
|
|
|
|
|
*/
|
|
|
|
|
public Message response;
|
|
|
|
|
private volatile Message response;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The field where we would store the first error we receive from a DNS
|
|
|
|
|
@ -470,12 +465,12 @@ private class ParallelResolution extends Thread
|
|
|
|
|
/**
|
|
|
|
|
* Indicates whether we are still waiting for an answer from someone
|
|
|
|
|
*/
|
|
|
|
|
private boolean done = false;
|
|
|
|
|
private volatile boolean done = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Indicates that a response was received from the primary resolver.
|
|
|
|
|
*/
|
|
|
|
|
private boolean primaryResolverRespondedFirst = true;
|
|
|
|
|
private volatile boolean primaryResolverRespondedFirst = true;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a {@link ParallelResolution} for the specified <tt>query</tt>
|
|
|
|
|
@ -485,7 +480,6 @@ private class ParallelResolution extends Thread
|
|
|
|
|
*/
|
|
|
|
|
public ParallelResolution(final Message query)
|
|
|
|
|
{
|
|
|
|
|
super("ParallelResolutionThread");
|
|
|
|
|
this.query = query;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -495,7 +489,7 @@ public ParallelResolution(final Message query)
|
|
|
|
|
*/
|
|
|
|
|
public void sendFirstQuery()
|
|
|
|
|
{
|
|
|
|
|
start();
|
|
|
|
|
ParallelResolverImpl.this.backupQueriesPool.execute(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -509,19 +503,24 @@ public void run()
|
|
|
|
|
{
|
|
|
|
|
localResponse = defaultResolver.send(query);
|
|
|
|
|
}
|
|
|
|
|
catch (Throwable exc)
|
|
|
|
|
catch (SocketTimeoutException exc)
|
|
|
|
|
{
|
|
|
|
|
logger.info("Exception occurred during parallel DNS resolving" +
|
|
|
|
|
exc, exc);
|
|
|
|
|
logger.info("Default DNS resolver timed out.");
|
|
|
|
|
this.exception = exc;
|
|
|
|
|
}
|
|
|
|
|
synchronized(this)
|
|
|
|
|
catch (Throwable exc)
|
|
|
|
|
{
|
|
|
|
|
logger.info("Default DNS resolver failed", exc);
|
|
|
|
|
this.exception = exc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//if the backup resolvers had already replied we ignore the
|
|
|
|
|
//reply of the primary one whatever it was.
|
|
|
|
|
if(done)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
synchronized(this)
|
|
|
|
|
{
|
|
|
|
|
//if there was a response we're only done if it is satisfactory
|
|
|
|
|
if( localResponse != null
|
|
|
|
|
&& isResponseSatisfactory(localResponse))
|
|
|
|
|
@ -529,6 +528,7 @@ && isResponseSatisfactory(localResponse))
|
|
|
|
|
response = localResponse;
|
|
|
|
|
done = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
notify();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -538,22 +538,25 @@ && isResponseSatisfactory(localResponse))
|
|
|
|
|
*/
|
|
|
|
|
public void sendBackupQueries()
|
|
|
|
|
{
|
|
|
|
|
logger.info("Send DNS queries to backup resolvers");
|
|
|
|
|
|
|
|
|
|
//yes. a second thread in the thread ... it's ugly but it works
|
|
|
|
|
//and i do want to keep code simple to read ... this whole parallel
|
|
|
|
|
//resolving is complicated enough as it is.
|
|
|
|
|
new Thread(){
|
|
|
|
|
backupQueriesPool.execute(new Runnable(){
|
|
|
|
|
@Override
|
|
|
|
|
public void run()
|
|
|
|
|
{
|
|
|
|
|
synchronized(ParallelResolution.this)
|
|
|
|
|
{
|
|
|
|
|
if (done)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Message localResponse = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
logger.info("Sending query for "
|
|
|
|
|
+ query.getQuestion().getName() + "/"
|
|
|
|
|
+ Type.string(query.getQuestion().getType())
|
|
|
|
|
+ " to backup resolvers");
|
|
|
|
|
localResponse = backupResolver.send(query);
|
|
|
|
|
}
|
|
|
|
|
catch (Throwable exc)
|
|
|
|
|
@ -567,18 +570,26 @@ public void run()
|
|
|
|
|
//if the default resolver has already replied we
|
|
|
|
|
//ignore the reply of the backup ones.
|
|
|
|
|
if(done)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
synchronized(ParallelResolution.this)
|
|
|
|
|
{
|
|
|
|
|
//contrary to responses from the primary resolver,
|
|
|
|
|
//in this case we don't care whether the response is
|
|
|
|
|
//satisfying: if it isn't, there's nothing we can do
|
|
|
|
|
if (response == null)
|
|
|
|
|
{
|
|
|
|
|
response = localResponse;
|
|
|
|
|
done = true;
|
|
|
|
|
primaryResolverRespondedFirst = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done = true;
|
|
|
|
|
ParallelResolution.this.notify();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}.start();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -636,6 +647,11 @@ public Message returnResponseOrThrowUp()
|
|
|
|
|
{
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
else if (exception instanceof SocketTimeoutException)
|
|
|
|
|
{
|
|
|
|
|
logger.warn("DNS resolver timed out");
|
|
|
|
|
throw (IOException) exception;
|
|
|
|
|
}
|
|
|
|
|
else if (exception instanceof IOException)
|
|
|
|
|
{
|
|
|
|
|
logger.warn("IO exception while using DNS resolver", exception);
|
|
|
|
|
@ -664,6 +680,7 @@ else if (exception instanceof Error)
|
|
|
|
|
@SuppressWarnings("serial")
|
|
|
|
|
private final Set<String> configNames = new HashSet<String>(5)
|
|
|
|
|
{{
|
|
|
|
|
add(DnsUtilActivator.PNAME_BACKUP_RESOLVER_ENABLED);
|
|
|
|
|
add(DnsUtilActivator.PNAME_BACKUP_RESOLVER);
|
|
|
|
|
add(DnsUtilActivator.PNAME_BACKUP_RESOLVER_FALLBACK_IP);
|
|
|
|
|
add(DnsUtilActivator.PNAME_BACKUP_RESOLVER_PORT);
|
|
|
|
|
|