I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit c639525c authored by zzz's avatar zzz
Browse files

* Timestamper:

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