* Timestamper:
- Use GeoIP to query a closer ntp source if available - Lengthen query time if well-synced - Cleanup
This commit is contained in:
@ -17,17 +17,20 @@ import net.i2p.util.Log;
|
||||
public class Timestamper implements Runnable {
|
||||
private I2PAppContext _context;
|
||||
private Log _log;
|
||||
private List _servers;
|
||||
private List _listeners;
|
||||
private List<String> _servers;
|
||||
private List<String> _priorityServers;
|
||||
private List<UpdateListener> _listeners;
|
||||
private int _queryFrequency;
|
||||
private int _concurringServers;
|
||||
private volatile boolean _disabled;
|
||||
private boolean _daemon;
|
||||
private boolean _initialized;
|
||||
private boolean _wellSynced;
|
||||
|
||||
private static final int MIN_QUERY_FREQUENCY = 5*60*1000;
|
||||
private static final int DEFAULT_QUERY_FREQUENCY = 5*60*1000;
|
||||
private static final String DEFAULT_SERVER_LIST = "0.pool.ntp.org, 1.pool.ntp.org, 2.pool.ntp.org";
|
||||
private static final boolean DEFAULT_DISABLED = true;
|
||||
private static final String DEFAULT_SERVER_LIST = "0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org";
|
||||
private static final String DEFAULT_DISABLED = "true";
|
||||
/** how many times do we have to query if we are changing the clock? */
|
||||
private static final int DEFAULT_CONCURRING_SERVERS = 3;
|
||||
|
||||
@ -35,6 +38,7 @@ public class Timestamper implements Runnable {
|
||||
public static final String PROP_SERVER_LIST = "time.sntpServerList";
|
||||
public static final String PROP_DISABLED = "time.disabled";
|
||||
public static final String PROP_CONCURRING_SERVERS = "time.concurringServers";
|
||||
public static final String PROP_IP_COUNTRY = "i2np.lastCountry";
|
||||
|
||||
/** if different SNTP servers differ by more than 10s, someone is b0rked */
|
||||
private static final int MAX_VARIANCE = 10*1000;
|
||||
@ -50,7 +54,8 @@ public class Timestamper implements Runnable {
|
||||
_context = ctx;
|
||||
_daemon = daemon;
|
||||
_initialized = false;
|
||||
_servers = new ArrayList(1);
|
||||
_wellSynced = false;
|
||||
_servers = new ArrayList(3);
|
||||
_listeners = new ArrayList(1);
|
||||
if (lsnr != null)
|
||||
_listeners.add(lsnr);
|
||||
@ -115,36 +120,47 @@ public class Timestamper implements Runnable {
|
||||
_log = _context.logManager().getLog(Timestamper.class);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Starting timestamper");
|
||||
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Starting up timestamper");
|
||||
boolean lastFailed = false;
|
||||
try {
|
||||
while (true) {
|
||||
updateConfig();
|
||||
if (!_disabled) {
|
||||
String serverList[] = null;
|
||||
synchronized (_servers) {
|
||||
serverList = new String[_servers.size()];
|
||||
for (int i = 0; i < serverList.length; i++)
|
||||
serverList[i] = (String)_servers.get(i);
|
||||
// first the servers for our country, if we know what country we're in...
|
||||
if (_priorityServers != null) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Querying servers " + _priorityServers);
|
||||
try {
|
||||
lastFailed = !queryTime(_priorityServers.toArray(new String[_priorityServers.size()]));
|
||||
} catch (IllegalArgumentException iae) {
|
||||
if ( (!lastFailed) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Unable to reach country-specific NTP servers");
|
||||
lastFailed = true;
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Querying servers " + _servers);
|
||||
try {
|
||||
lastFailed = !queryTime(serverList);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
if ( (!lastFailed) && (_log.shouldLog(Log.ERROR)) )
|
||||
_log.error("Unable to reach any of the NTP servers - network disconnected?");
|
||||
lastFailed = true;
|
||||
// ... and then the global list, if that failed
|
||||
if (_priorityServers == null || lastFailed) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Querying servers " + _servers);
|
||||
try {
|
||||
lastFailed = !queryTime(_servers.toArray(new String[_servers.size()]));
|
||||
} catch (IllegalArgumentException iae) {
|
||||
if ( (!lastFailed) && (_log.shouldLog(Log.ERROR)) )
|
||||
_log.error("Unable to reach any of the NTP servers - network disconnected?");
|
||||
lastFailed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
synchronized (this) { notifyAll(); }
|
||||
long sleepTime = _context.random().nextInt(_queryFrequency) + _queryFrequency;
|
||||
if (lastFailed)
|
||||
long sleepTime;
|
||||
if (lastFailed) {
|
||||
sleepTime = 30*1000;
|
||||
} else {
|
||||
sleepTime = _context.random().nextInt(_queryFrequency) + _queryFrequency;
|
||||
if (_wellSynced)
|
||||
sleepTime *= 3;
|
||||
}
|
||||
try { Thread.sleep(sleepTime); } catch (InterruptedException ie) {}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
@ -160,6 +176,7 @@ public class Timestamper implements Runnable {
|
||||
long found[] = new long[_concurringServers];
|
||||
long now = -1;
|
||||
long expectedDelta = 0;
|
||||
_wellSynced = false;
|
||||
for (int i = 0; i < _concurringServers; i++) {
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
now = NtpClient.currentTime(serverList);
|
||||
@ -169,6 +186,8 @@ public class Timestamper implements Runnable {
|
||||
if (Math.abs(delta) < MAX_VARIANCE) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("a single SNTP query was within the tolerance (" + delta + "ms)");
|
||||
// If less than a half second on the first try, we're in good shape
|
||||
_wellSynced = Math.abs(delta) < 500;
|
||||
break;
|
||||
} else {
|
||||
// outside the tolerance, lets iterate across the concurring queries
|
||||
@ -224,56 +243,36 @@ public class Timestamper implements Runnable {
|
||||
*/
|
||||
private void updateConfig() {
|
||||
String serverList = _context.getProperty(PROP_SERVER_LIST);
|
||||
if ( (serverList == null) || (serverList.trim().length() <= 0) )
|
||||
if ( (serverList == null) || (serverList.trim().length() <= 0) ) {
|
||||
serverList = DEFAULT_SERVER_LIST;
|
||||
synchronized (_servers) {
|
||||
_servers.clear();
|
||||
StringTokenizer tok = new StringTokenizer(serverList, ",");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String val = (String)tok.nextToken();
|
||||
val = val.trim();
|
||||
if (val.length() > 0)
|
||||
_servers.add(val);
|
||||
}
|
||||
}
|
||||
|
||||
String freq = _context.getProperty(PROP_QUERY_FREQUENCY);
|
||||
if ( (freq == null) || (freq.trim().length() <= 0) )
|
||||
freq = DEFAULT_QUERY_FREQUENCY + "";
|
||||
try {
|
||||
int ms = Integer.parseInt(freq);
|
||||
if (ms > 60*1000) {
|
||||
_queryFrequency = ms;
|
||||
String country = _context.getProperty(PROP_IP_COUNTRY);
|
||||
if (country != null) {
|
||||
_priorityServers = new ArrayList(3);
|
||||
for (int i = 0; i < 3; i++)
|
||||
_priorityServers.add(i + "." + country + ".pool.ntp.org");
|
||||
} else {
|
||||
if ( (_log != null) && (_log.shouldLog(Log.ERROR)) )
|
||||
_log.error("Query frequency once every " + ms + "ms is too fast!");
|
||||
_queryFrequency = DEFAULT_QUERY_FREQUENCY;
|
||||
_priorityServers = null;
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
if ( (_log != null) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Invalid query frequency [" + freq + "], falling back on " + DEFAULT_QUERY_FREQUENCY);
|
||||
_queryFrequency = DEFAULT_QUERY_FREQUENCY;
|
||||
} else {
|
||||
_priorityServers = null;
|
||||
}
|
||||
_servers.clear();
|
||||
StringTokenizer tok = new StringTokenizer(serverList, ", ");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String val = (String)tok.nextToken();
|
||||
val = val.trim();
|
||||
if (val.length() > 0)
|
||||
_servers.add(val);
|
||||
}
|
||||
|
||||
String disabled = _context.getProperty(PROP_DISABLED);
|
||||
if (disabled == null)
|
||||
disabled = DEFAULT_DISABLED + "";
|
||||
_queryFrequency = Math.max(MIN_QUERY_FREQUENCY,
|
||||
_context.getProperty(PROP_QUERY_FREQUENCY, DEFAULT_QUERY_FREQUENCY));
|
||||
|
||||
String disabled = _context.getProperty(PROP_DISABLED, DEFAULT_DISABLED);
|
||||
_disabled = Boolean.valueOf(disabled).booleanValue();
|
||||
|
||||
String concurring = _context.getProperty(PROP_CONCURRING_SERVERS);
|
||||
if (concurring == null) {
|
||||
_concurringServers = DEFAULT_CONCURRING_SERVERS;
|
||||
} else {
|
||||
try {
|
||||
int servers = Integer.parseInt(concurring);
|
||||
if ( (servers > 0) && (servers < 5) )
|
||||
_concurringServers = servers;
|
||||
else
|
||||
_concurringServers = DEFAULT_CONCURRING_SERVERS;
|
||||
} catch (NumberFormatException nfe) {
|
||||
_concurringServers = DEFAULT_CONCURRING_SERVERS;
|
||||
}
|
||||
}
|
||||
_concurringServers = Math.min(4, Math.max(1,
|
||||
_context.getProperty(PROP_CONCURRING_SERVERS, DEFAULT_CONCURRING_SERVERS)));
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
@ -297,4 +296,4 @@ public class Timestamper implements Runnable {
|
||||
*/
|
||||
public void setNow(long now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user