From f11a5432338ff503c8e26a3817d1ed8fcda8b2cf Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Fri, 11 Feb 2011 23:59:10 +0000 Subject: [PATCH] * Clock: Cleanups and javadocs * EepGet: Cleanups and javadocs * Reseed: Use the reseeder as a clock source --- .../i2p/client/streaming/I2PSocketEepGet.java | 1 - .../src/net/i2p/router/web/NewsFetcher.java | 45 +----------- .../i2p/router/web/UnsignedUpdateHandler.java | 3 +- .../src/net/i2p/router/web/UpdateHandler.java | 3 +- core/java/src/net/i2p/time/Timestamper.java | 18 ++--- core/java/src/net/i2p/util/Clock.java | 13 +++- core/java/src/net/i2p/util/EepGet.java | 41 +++++------ .../java/src/net/i2p/router/RouterClock.java | 18 +++-- .../i2p/router/networkdb/reseed/Reseeder.java | 70 ++++++++++++++++--- .../transport/CommSystemFacadeImpl.java | 2 +- .../router/transport/ntcp/EstablishState.java | 4 +- .../router/transport/udp/PacketHandler.java | 2 +- .../src/net/i2p/router/util/RFC822Date.java | 51 ++++++++++++++ 13 files changed, 169 insertions(+), 102 deletions(-) create mode 100644 router/java/src/net/i2p/router/util/RFC822Date.java diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketEepGet.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketEepGet.java index 834c52160c..d68270bc62 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketEepGet.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketEepGet.java @@ -59,7 +59,6 @@ public class I2PSocketEepGet extends EepGet { // public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize, String outputFile, OutputStream outputStream, String url, boolean allowCaching, String etag, String postData) { super(ctx, false, null, -1, numRetries, minSize, maxSize, outputFile, outputStream, url, true, null, null); _socketManager = mgr; - _log = ctx.logManager().getLog(I2PSocketEepGet.class); } /** diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java index adb2380777..562c3e7cad 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java @@ -3,11 +3,9 @@ package net.i2p.router.web; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; -import java.util.Locale; import net.i2p.I2PAppContext; import net.i2p.crypto.TrustedUpdate; @@ -15,6 +13,7 @@ import net.i2p.data.DataHelper; import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.router.RouterVersion; +import net.i2p.router.util.RFC822Date; import net.i2p.util.EepGet; import net.i2p.util.EepHead; import net.i2p.util.FileUtil; @@ -73,7 +72,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { if (_lastFetch == 0) _lastFetch = _lastUpdated; if (_lastModified == null) - _lastModified = to822Date(_lastFetch); + _lastModified = RFC822Date.to822Date(_lastFetch); } else { _lastUpdated = 0; _lastFetch = 0; @@ -212,7 +211,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { String lastmod = get.getLastModified(); if (lastmod != null) { if (!(_context.isRouterContext())) return; - long modtime = parse822Date(lastmod); + long modtime = RFC822Date.parse822Date(lastmod); if (modtime <= 0) return; String lastUpdate = _context.getProperty(UpdateHandler.PROP_LAST_UPDATE_TIME); if (lastUpdate == null) { @@ -251,44 +250,6 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { handler.update(); } - /** - * http://jimyjoshi.com/blog/2007/08/rfc822dateparsinginjava.html - * Apparently public domain - * Probably don't need all of these... - */ - private static final SimpleDateFormat rfc822DateFormats[] = new SimpleDateFormat[] { - new SimpleDateFormat("EEE, d MMM yy HH:mm:ss z", Locale.US), - new SimpleDateFormat("EEE, d MMM yy HH:mm z", Locale.US), - new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.US), - new SimpleDateFormat("EEE, d MMM yyyy HH:mm z", Locale.US), - new SimpleDateFormat("d MMM yy HH:mm z", Locale.US), - new SimpleDateFormat("d MMM yy HH:mm:ss z", Locale.US), - new SimpleDateFormat("d MMM yyyy HH:mm z", Locale.US), - new SimpleDateFormat("d MMM yyyy HH:mm:ss z", Locale.US) - }; - - /** - * new Date(String foo) is deprecated, so let's do this the hard way - * - * @param s non-null - * @return -1 on failure - */ - public static long parse822Date(String s) { - for (int i = 0; i < rfc822DateFormats.length; i++) { - try { - Date date = rfc822DateFormats[i].parse(s); - if (date != null) - return date.getTime(); - } catch (ParseException pe) {} - } - return -1; - } - - /** @since 0.8.2 */ - private static String to822Date(long t) { - return (new SimpleDateFormat("d MMM yyyy HH:mm:ss z", Locale.US)).format(new Date(t)); - } - private static final String VERSION_STRING = "version=\"" + RouterVersion.VERSION + "\""; private static final String VERSION_PREFIX = "version=\""; private void checkForUpdates() { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java index 8fcbd65c0b..5a52ee883a 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java @@ -4,6 +4,7 @@ import java.io.File; import net.i2p.router.Router; import net.i2p.router.RouterContext; +import net.i2p.router.util.RFC822Date; import net.i2p.util.EepGet; import net.i2p.util.FileUtil; import net.i2p.util.I2PAppThread; @@ -101,7 +102,7 @@ public class UnsignedUpdateHandler extends UpdateHandler { String lastmod = _get.getLastModified(); long modtime = 0; if (lastmod != null) - modtime = NewsFetcher.parse822Date(lastmod); + modtime = RFC822Date.parse822Date(lastmod); if (modtime <= 0) modtime = _context.clock().now(); _context.router().setConfigSetting(PROP_LAST_UPDATE_TIME, "" + modtime); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java index 174704ba67..423b9e52ad 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java @@ -15,6 +15,7 @@ import net.i2p.data.DataHelper; import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.router.RouterVersion; +import net.i2p.router.util.RFC822Date; import net.i2p.util.EepGet; import net.i2p.util.I2PAppThread; import net.i2p.util.Log; @@ -271,7 +272,7 @@ public class UpdateHandler { String lastmod = _get.getLastModified(); long modtime = 0; if (lastmod != null) - modtime = NewsFetcher.parse822Date(lastmod); + modtime = RFC822Date.parse822Date(lastmod); if (modtime <= 0) modtime = _context.clock().now(); _context.router().setConfigSetting(PROP_LAST_UPDATE_TIME, "" + modtime); diff --git a/core/java/src/net/i2p/time/Timestamper.java b/core/java/src/net/i2p/time/Timestamper.java index a84882215c..2c798bab6b 100644 --- a/core/java/src/net/i2p/time/Timestamper.java +++ b/core/java/src/net/i2p/time/Timestamper.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.StringTokenizer; +import java.util.concurrent.CopyOnWriteArrayList; import net.i2p.I2PAppContext; import net.i2p.util.I2PThread; @@ -56,7 +57,7 @@ public class Timestamper implements Runnable { public Timestamper(I2PAppContext ctx, UpdateListener lsnr, boolean daemon) { // moved here to prevent problems with synchronized statements. _servers = new ArrayList(3); - _listeners = new ArrayList(1); + _listeners = new CopyOnWriteArrayList(); // Don't bother starting a thread if we are disabled. // This means we no longer check every 5 minutes to see if we got enabled, // so the property must be set at startup. @@ -92,24 +93,16 @@ public class Timestamper implements Runnable { public boolean getIsDisabled() { return _disabled; } public void addListener(UpdateListener lsnr) { - synchronized (_listeners) { _listeners.add(lsnr); - } } public void removeListener(UpdateListener lsnr) { - synchronized (_listeners) { _listeners.remove(lsnr); - } } public int getListenerCount() { - synchronized (_listeners) { return _listeners.size(); - } } public UpdateListener getListener(int index) { - synchronized (_listeners) { return _listeners.get(index); - } } private void startTimestamper() { @@ -257,11 +250,8 @@ public class Timestamper implements Runnable { */ private void stampTime(long now, int stratum) { long before = _context.clock().now(); - synchronized (_listeners) { - for (int i = 0; i < _listeners.size(); i++) { - UpdateListener lsnr = _listeners.get(i); - lsnr.setNow(now, stratum); - } + for (UpdateListener lsnr : _listeners) { + lsnr.setNow(now, stratum); } if (_log.shouldLog(Log.DEBUG)) _log.debug("Stamped the time as " + now + " (delta=" + (now-before) + ")"); diff --git a/core/java/src/net/i2p/util/Clock.java b/core/java/src/net/i2p/util/Clock.java index 80696fc957..ee43af44cc 100644 --- a/core/java/src/net/i2p/util/Clock.java +++ b/core/java/src/net/i2p/util/Clock.java @@ -49,14 +49,22 @@ public class Clock implements Timestamper.UpdateListener { /** if the clock skewed changes by less than this, ignore the update (so we don't slide all over the place) */ public final static long MIN_OFFSET_CHANGE = 5 * 1000; + /** + * Specify how far away from the "correct" time the computer is - a positive + * value means that the system time is slow, while a negative value means the system time is fast. + * + * @param offsetMs the delta from System.currentTimeMillis() (NOT the delta from now()) + */ public void setOffset(long offsetMs) { setOffset(offsetMs, false); } /** * Specify how far away from the "correct" time the computer is - a positive - * value means that we are slow, while a negative value means we are fast. + * value means that the system time is slow, while a negative value means the system time is fast. * Warning - overridden in RouterClock + * + * @param offsetMs the delta from System.currentTimeMillis() (NOT the delta from now()) */ public void setOffset(long offsetMs, boolean force) { if (false) return; @@ -101,6 +109,9 @@ public class Clock implements Timestamper.UpdateListener { fireOffsetChanged(delta); } + /* + * @return the current delta from System.currentTimeMillis() in milliseconds + */ public long getOffset() { return _offset; } diff --git a/core/java/src/net/i2p/util/EepGet.java b/core/java/src/net/i2p/util/EepGet.java index 3ad84e6bbf..24155e59e7 100644 --- a/core/java/src/net/i2p/util/EepGet.java +++ b/core/java/src/net/i2p/util/EepGet.java @@ -28,21 +28,21 @@ import net.i2p.util.InternalSocket; * Bug: a malformed url http://example.i2p (no trailing '/') fails cryptically */ public class EepGet { - protected I2PAppContext _context; - protected Log _log; - protected boolean _shouldProxy; - private String _proxyHost; - private int _proxyPort; - protected int _numRetries; - private long _minSize; // minimum and maximum acceptable response size, -1 signifies unlimited, - private long _maxSize; // applied both against whole responses and chunks - protected String _outputFile; - protected OutputStream _outputStream; + protected final I2PAppContext _context; + protected final Log _log; + protected final boolean _shouldProxy; + private final String _proxyHost; + private final int _proxyPort; + protected final int _numRetries; + private final long _minSize; // minimum and maximum acceptable response size, -1 signifies unlimited, + private final long _maxSize; // applied both against whole responses and chunks + protected final String _outputFile; + protected final OutputStream _outputStream; /** url we were asked to fetch */ - protected String _url; + protected final String _url; /** the URL we actually fetch from (may differ from the _url in case of redirect) */ protected String _actualURL; - private String _postData; + private final String _postData; private boolean _allowCaching; protected final List<StatusListener> _listeners; @@ -106,7 +106,7 @@ public class EepGet { String outputFile, OutputStream outputStream, String url, boolean allowCaching, String etag, String lastModified, String postData) { _context = ctx; - _log = ctx.logManager().getLog(EepGet.class); + _log = ctx.logManager().getLog(getClass()); _shouldProxy = (proxyHost != null) && (proxyHost.length() > 0) && (proxyPort > 0) && shouldProxy; _proxyHost = proxyHost; _proxyPort = proxyPort; @@ -118,13 +118,7 @@ public class EepGet { _url = url; _actualURL = url; _postData = postData; - _alreadyTransferred = 0; - _bytesTransferred = 0; _bytesRemaining = -1; - _currentAttempt = 0; - _transferFailed = false; - _headersRead = false; - _aborted = false; _fetchHeaderTimeout = CONNECT_TIMEOUT; _listeners = new ArrayList(1); _etag = etag; @@ -255,9 +249,9 @@ public class EepGet { public void attempting(String url); } protected class CLIStatusListener implements StatusListener { - private int _markSize; - private int _lineSize; - private long _startedOn; + private final int _markSize; + private final int _lineSize; + private final long _startedOn; private long _written; private long _previousWritten; private long _discarded; @@ -271,9 +265,6 @@ public class EepGet { public CLIStatusListener(int markSize, int lineSize) { _markSize = markSize; _lineSize = lineSize; - _written = 0; - _previousWritten = 0; - _discarded = 0; _lastComplete = _context.clock().now(); _startedOn = _lastComplete; _firstTime = true; diff --git a/router/java/src/net/i2p/router/RouterClock.java b/router/java/src/net/i2p/router/RouterClock.java index fd15d7db38..3f7b629606 100644 --- a/router/java/src/net/i2p/router/RouterClock.java +++ b/router/java/src/net/i2p/router/RouterClock.java @@ -24,7 +24,7 @@ public class RouterClock extends Clock { * All of this is @since 0.7.12 */ private static final long MAX_SLEW = 50; - private static final int DEFAULT_STRATUM = 8; + public static final int DEFAULT_STRATUM = 8; private static final int WORST_STRATUM = 16; /** the max NTP Timestamper delay is 30m right now, make this longer than that */ private static final long MIN_DELAY_FOR_WORSE_STRATUM = 45*60*1000; @@ -44,20 +44,27 @@ public class RouterClock extends Clock { /** * Specify how far away from the "correct" time the computer is - a positive - * value means that we are slow, while a negative value means we are fast. + * value means that the system time is slow, while a negative value means the system time is fast. * + * @param offsetMs the delta from System.currentTimeMillis() (NOT the delta from now()) */ @Override public void setOffset(long offsetMs, boolean force) { setOffset(offsetMs, force, DEFAULT_STRATUM); } - /** @since 0.7.12 */ + /** + * @since 0.7.12 + * @param offsetMs the delta from System.currentTimeMillis() (NOT the delta from now()) + */ private void setOffset(long offsetMs, int stratum) { setOffset(offsetMs, false, stratum); } - /** @since 0.7.12 */ + /** + * @since 0.7.12 + * @param offsetMs the delta from System.currentTimeMillis() (NOT the delta from now()) + */ private void setOffset(long offsetMs, boolean force, int stratum) { long delta = offsetMs - _offset; if (!force) { @@ -91,7 +98,7 @@ public class RouterClock extends Clock { } // If so configured, check sanity of proposed clock offset - if (Boolean.valueOf(_contextRC.getProperty("router.clockOffsetSanityCheck","true")).booleanValue() && + if (_contextRC.getBooleanPropertyDefaultTrue("router.clockOffsetSanityCheck") && _alreadyChanged) { // Try calculating peer clock skew @@ -192,6 +199,7 @@ public class RouterClock extends Clock { /* * How far we still have to slew, for diagnostics * @since 0.7.12 + * @deprecated for debugging only */ public long getDeltaOffset() { return _desiredOffset - _offset; diff --git a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java index 4c4c2ce91f..93933aa51c 100644 --- a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java +++ b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java @@ -14,7 +14,10 @@ import java.util.Set; import java.util.StringTokenizer; import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; +import net.i2p.router.RouterClock; import net.i2p.router.RouterContext; +import net.i2p.router.util.RFC822Date; import net.i2p.util.EepGet; import net.i2p.util.I2PAppThread; import net.i2p.util.Log; @@ -34,6 +37,7 @@ import net.i2p.util.Translate; * the router log, and the wrapper log. */ public class Reseeder { + /** FIXME don't keep a static reference, store _isRunning some other way */ private static ReseedRunner _reseedRunner; private final RouterContext _context; private final Log _log; @@ -46,6 +50,10 @@ public class Reseeder { /** * NOTE - URLs in both the standard and SSL groups should use the same hostname and path, * so the reseed process will not download from both. + * + * NOTE - Each seedURL must be a directory, it must end with a '/', + * it can't end with 'index.html', for example. Both because of how individual file + * URLs are constructed, and because SSLEepGet doesn't follow redirects. */ public static final String DEFAULT_SEED_URL = "http://a.netdb.i2p2.de/,http://c.netdb.i2p2.de/," + @@ -98,13 +106,13 @@ public class Reseeder { private String _proxyHost; private int _proxyPort; private SSLEepGet.SSLState _sslState; + private int _gotDate; + private long _attemptStarted; + private static final int MAX_DATE_SETS = 2; public ReseedRunner() { - _isRunning = false; - System.clearProperty(PROP_ERROR); - System.setProperty(PROP_STATUS, _("Reseeding")); - System.setProperty(PROP_INPROGRESS, "true"); } + public boolean isRunning() { return _isRunning; } /* @@ -113,6 +121,11 @@ public class Reseeder { */ public void run() { _isRunning = true; + System.clearProperty(PROP_ERROR); + System.setProperty(PROP_STATUS, _("Reseeding")); + System.setProperty(PROP_INPROGRESS, "true"); + _attemptStarted = 0; + _gotDate = 0; _sslState = null; // start fresh if (_context.getBooleanProperty(PROP_PROXY_ENABLE)) { _proxyHost = _context.getProperty(PROP_PROXY_HOST); @@ -152,8 +165,48 @@ public class Reseeder { public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {} public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {} public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {} - public void headerReceived(String url, int attemptNum, String key, String val) {} - public void attempting(String url) {} + + /** + * Use the Date header as a backup time source + */ + public void headerReceived(String url, int attemptNum, String key, String val) { + // We do this more than once, because + // the first SSL handshake may take a while, and it may take the server + // a while to render the index page. + if (_gotDate < MAX_DATE_SETS && "date".equalsIgnoreCase(key) && _attemptStarted > 0) { + long timeRcvd = System.currentTimeMillis(); + long serverTime = RFC822Date.parse822Date(val); + if (serverTime > 0) { + // add 500ms since it's 1-sec resolution, and add half the RTT + long now = serverTime + 500 + ((timeRcvd - _attemptStarted) / 2); + long offset = now - _context.clock().now(); + if (_context.clock().getUpdatedSuccessfully()) { + // 2nd time better than the first + if (_gotDate > 0) + _context.clock().setNow(now, RouterClock.DEFAULT_STRATUM - 2); + else + _context.clock().setNow(now, RouterClock.DEFAULT_STRATUM - 1); + if (_log.shouldLog(Log.WARN)) + _log.warn("Reseed adjusting clock by " + + DataHelper.formatDuration(Math.abs(offset))); + } else { + // No peers or NTP yet, this is probably better than the peer average will be for a while + // default stratum - 1, so the peer average is a worse stratum + _context.clock().setNow(now, RouterClock.DEFAULT_STRATUM - 1); + _log.logAlways(Log.WARN, "NTP failure, Reseed adjusting clock by " + + DataHelper.formatDuration(Math.abs(offset))); + } + _gotDate++; + } + } + } + + /** save the start time */ + public void attempting(String url) { + if (_gotDate < MAX_DATE_SETS) + _attemptStarted = System.currentTimeMillis(); + } + // End of EepGet status listeners /** @@ -235,7 +288,8 @@ public class Reseeder { **/ private int reseedOne(String seedURL, boolean echoStatus) { try { - final long timeLimit = _context.clock().now() + MAX_TIME_PER_HOST; + // Don't use context clock as we may be adjusting the time + final long timeLimit = System.currentTimeMillis() + MAX_TIME_PER_HOST; System.setProperty(PROP_STATUS, _("Reseeding: fetching seed URL.")); System.err.println("Reseeding from " + seedURL); URL dir = new URL(seedURL); @@ -275,7 +329,7 @@ public class Reseeder { int errors = 0; // 200 max from one URL for (Iterator<String> iter = urlList.iterator(); - iter.hasNext() && fetched < 200 && _context.clock().now() < timeLimit; ) { + iter.hasNext() && fetched < 200 && System.currentTimeMillis() < timeLimit; ) { try { System.setProperty(PROP_STATUS, _("Reseeding: fetching router info from seed URL ({0} successful, {1} errors).", fetched, errors)); diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java index d7849d5320..780a25d6b2 100644 --- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java +++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java @@ -509,7 +509,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade { buf.append("<tt>"); boolean found = _context.netDb().lookupRouterInfoLocally(peer) != null; if (found) - buf.append("<a title=\"").append(_("NetDb entry")).append("\" href=\"netdb.jsp?r=").append(h).append("\">"); + buf.append("<a title=\"").append(_("NetDb entry")).append("\" href=\"netdb?r=").append(h).append("\">"); buf.append(h); if (found) buf.append("</a>"); diff --git a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java index d6109c6406..3dfc1b8934 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java +++ b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java @@ -399,7 +399,7 @@ class EstablishState { _context.clock().setOffset(1000 * (_tsB - _tsA), true); _tsA = _tsB; if (diff != 0) - _log.error("NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff)); + _log.logAlways(Log.WARN, "NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff)); } else if (diff >= Router.CLOCK_FUDGE_FACTOR) { _context.statManager().addRateData("ntcp.invalidOutboundSkew", diff, 0); _transport.markReachable(_con.getRemotePeer().calculateHash(), false); @@ -617,7 +617,7 @@ class EstablishState { _context.clock().setOffset(1000 * (_tsB - tsA), true); tsA = _tsB; if (diff != 0) - _log.error("NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff)); + _log.logAlways(Log.WARN, "NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff)); } else if (diff >= Router.CLOCK_FUDGE_FACTOR) { _context.statManager().addRateData("ntcp.invalidInboundSkew", diff, 0); _transport.markReachable(alice.calculateHash(), true); diff --git a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java index 230c1b7921..ffbcf48aca 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java @@ -473,7 +473,7 @@ class PacketHandler { // so we have to wait for NTCP to do it _context.clock().setOffset(0 - skew, true); if (skew != 0) - _log.error("NTP failure, UDP adjusting clock by " + DataHelper.formatDuration(Math.abs(skew))); + _log.logAlways(Log.WARN, "NTP failure, UDP adjusting clock by " + DataHelper.formatDuration(Math.abs(skew))); } if (skew > GRACE_PERIOD) { diff --git a/router/java/src/net/i2p/router/util/RFC822Date.java b/router/java/src/net/i2p/router/util/RFC822Date.java new file mode 100644 index 0000000000..6635bca8cf --- /dev/null +++ b/router/java/src/net/i2p/router/util/RFC822Date.java @@ -0,0 +1,51 @@ +package net.i2p.router.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * Moved from NewsFetcher + * @since 0.8.5 + */ +public abstract class RFC822Date { + + /** + * http://jimyjoshi.com/blog/2007/08/rfc822dateparsinginjava.html + * Apparently public domain + * Probably don't need all of these... + */ + private static final SimpleDateFormat rfc822DateFormats[] = new SimpleDateFormat[] { + new SimpleDateFormat("EEE, d MMM yy HH:mm:ss z", Locale.US), + new SimpleDateFormat("EEE, d MMM yy HH:mm z", Locale.US), + new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.US), + new SimpleDateFormat("EEE, d MMM yyyy HH:mm z", Locale.US), + new SimpleDateFormat("d MMM yy HH:mm z", Locale.US), + new SimpleDateFormat("d MMM yy HH:mm:ss z", Locale.US), + new SimpleDateFormat("d MMM yyyy HH:mm z", Locale.US), + new SimpleDateFormat("d MMM yyyy HH:mm:ss z", Locale.US) + }; + + /** + * new Date(String foo) is deprecated, so let's do this the hard way + * + * @param s non-null + * @return -1 on failure + */ + public static long parse822Date(String s) { + for (int i = 0; i < rfc822DateFormats.length; i++) { + try { + Date date = rfc822DateFormats[i].parse(s); + if (date != null) + return date.getTime(); + } catch (ParseException pe) {} + } + return -1; + } + + /** @since 0.8.2 */ + public static String to822Date(long t) { + return (new SimpleDateFormat("d MMM yyyy HH:mm:ss z", Locale.US)).format(new Date(t)); + } +} -- GitLab