Router timestamper:

- Add country-to-continent mapping
 - Add continent pool.ntp.org zones as first fallback,
   this will improve time service for countries that don't have a zone
 - Don't start threads in constructors
 - Fix logging, better prevention of initialization loops
 - Log severe errors to wrapper log also
continent.txt file from http://dev.maxmind.com/geoip/legacy/codes/country_continent/
Creative Commons Attribution-ShareAlike 3.0 Unported License
http://dev.maxmind.com/geoip/legacy/geolite/
Terms already met in LICENSE.txt
This commit is contained in:
zzz
2015-04-21 14:22:05 +00:00
parent fd82fff07a
commit 1caf3e778b
7 changed files with 504 additions and 45 deletions

View File

@ -1405,6 +1405,7 @@
<copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" /> <copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
<!-- small enough to include for now --> <!-- small enough to include for now -->
<copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" /> <copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" />
<copy file="installer/resources/continents.txt" todir="pkg-temp/geoip/" />
</target> </target>
<target name="prepupdateRouter" depends="buildrouter, deletepkg-temp"> <target name="prepupdateRouter" depends="buildrouter, deletepkg-temp">
@ -1422,6 +1423,7 @@
<copy file="installer/resources/geoip.txt" todir="pkg-temp/geoip/" /> <copy file="installer/resources/geoip.txt" todir="pkg-temp/geoip/" />
<copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" /> <copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" />
<copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" /> <copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
<copy file="installer/resources/continents.txt" todir="pkg-temp/geoip/" />
</target> </target>
<!-- All jetty jars required for update. <!-- All jetty jars required for update.

View File

@ -0,0 +1,255 @@
# From http://dev.maxmind.com/static/csv/codes/country_continent.csv
# Fetched 2015-04-21
#"iso 3166 country","continent code"
A1,--
A2,--
AD,EU
AE,AS
AF,AS
AG,NA
AI,NA
AL,EU
AM,AS
AN,NA
AO,AF
AP,AS
AQ,AN
AR,SA
AS,OC
AT,EU
AU,OC
AW,NA
AX,EU
AZ,AS
BA,EU
BB,NA
BD,AS
BE,EU
BF,AF
BG,EU
BH,AS
BI,AF
BJ,AF
BL,NA
BM,NA
BN,AS
BO,SA
BR,SA
BS,NA
BT,AS
BV,AN
BW,AF
BY,EU
BZ,NA
CA,NA
CC,AS
CD,AF
CF,AF
CG,AF
CH,EU
CI,AF
CK,OC
CL,SA
CM,AF
CN,AS
CO,SA
CR,NA
CU,NA
CV,AF
CX,AS
CY,AS
CZ,EU
DE,EU
DJ,AF
DK,EU
DM,NA
DO,NA
DZ,AF
EC,SA
EE,EU
EG,AF
EH,AF
ER,AF
ES,EU
ET,AF
EU,EU
FI,EU
FJ,OC
FK,SA
FM,OC
FO,EU
FR,EU
FX,EU
GA,AF
GB,EU
GD,NA
GE,AS
GF,SA
GG,EU
GH,AF
GI,EU
GL,NA
GM,AF
GN,AF
GP,NA
GQ,AF
GR,EU
GS,AN
GT,NA
GU,OC
GW,AF
GY,SA
HK,AS
HM,AN
HN,NA
HR,EU
HT,NA
HU,EU
ID,AS
IE,EU
IL,AS
IM,EU
IN,AS
IO,AS
IQ,AS
IR,AS
IS,EU
IT,EU
JE,EU
JM,NA
JO,AS
JP,AS
KE,AF
KG,AS
KH,AS
KI,OC
KM,AF
KN,NA
KP,AS
KR,AS
KW,AS
KY,NA
KZ,AS
LA,AS
LB,AS
LC,NA
LI,EU
LK,AS
LR,AF
LS,AF
LT,EU
LU,EU
LV,EU
LY,AF
MA,AF
MC,EU
MD,EU
ME,EU
MF,NA
MG,AF
MH,OC
MK,EU
ML,AF
MM,AS
MN,AS
MO,AS
MP,OC
MQ,NA
MR,AF
MS,NA
MT,EU
MU,AF
MV,AS
MW,AF
MX,NA
MY,AS
MZ,AF
NA,AF
NC,OC
NE,AF
NF,OC
NG,AF
NI,NA
NL,EU
NO,EU
NP,AS
NR,OC
NU,OC
NZ,OC
O1,--
OM,AS
PA,NA
PE,SA
PF,OC
PG,OC
PH,AS
PK,AS
PL,EU
PM,NA
PN,OC
PR,NA
PS,AS
PT,EU
PW,OC
PY,SA
QA,AS
RE,AF
RO,EU
RS,EU
RU,EU
RW,AF
SA,AS
SB,OC
SC,AF
SD,AF
SE,EU
SG,AS
SH,AF
SI,EU
SJ,EU
SK,EU
SL,AF
SM,EU
SN,AF
SO,AF
SR,SA
ST,AF
SV,NA
SY,AS
SZ,AF
TC,NA
TD,AF
TF,AN
TG,AF
TH,AS
TJ,AS
TK,OC
TL,AS
TM,AS
TN,AF
TO,OC
TR,EU
TT,NA
TV,OC
TW,AS
TZ,AF
UA,EU
UG,AF
UM,OC
US,NA
UY,SA
UZ,AS
VA,EU
VC,NA
VE,SA
VG,NA
VI,NA
VN,AS
VU,OC
WF,OC
WS,OC
YE,AS
YT,AF
ZA,AF
ZM,AF
ZW,AF

View File

@ -40,7 +40,7 @@ public class RouterClock extends Clock {
/** use system time for this */ /** use system time for this */
private long _lastChanged; private long _lastChanged;
private int _lastStratum; private int _lastStratum;
private final Timestamper _timeStamper; private final RouterTimestamper _timeStamper;
/** /**
* If the system clock shifts by this much, * If the system clock shifts by this much,
@ -53,6 +53,9 @@ public class RouterClock extends Clock {
private final Set<ClockShiftListener> _shiftListeners; private final Set<ClockShiftListener> _shiftListeners;
private volatile long _lastShiftNanos; private volatile long _lastShiftNanos;
/**
* Does not start. Caller MUST call start()
*/
public RouterClock(RouterContext context) { public RouterClock(RouterContext context) {
super(context); super(context);
_lastStratum = WORST_STRATUM; _lastStratum = WORST_STRATUM;
@ -62,6 +65,14 @@ public class RouterClock extends Clock {
_timeStamper = new RouterTimestamper(context, this); _timeStamper = new RouterTimestamper(context, this);
} }
/**
* Cannot be stopped, but RouterTimestamper registers a shutdown task.
* @since 0.9.20
*/
public void start() {
_timeStamper.startTimestamper();
}
/** /**
* The RouterTimestamper * The RouterTimestamper
*/ */

View File

@ -483,8 +483,11 @@ public class RouterContext extends I2PAppContext {
@Override @Override
protected void initializeClock() { protected void initializeClock() {
synchronized (_lock1) { synchronized (_lock1) {
if (_clock == null) if (_clock == null) {
_clock = new RouterClock(this); RouterClock rc = new RouterClock(this);
rc.start();
_clock = rc;
}
_clockInitialized = true; _clockInitialized = true;
} }
} }

View File

@ -20,9 +20,10 @@ import net.i2p.util.Log;
*/ */
public class RouterTimestamper extends Timestamper { public class RouterTimestamper extends Timestamper {
private final I2PAppContext _context; private final I2PAppContext _context;
// warning, may be null
private Log _log; private Log _log;
private final List<String> _servers; private final List<String> _servers;
private List<String> _priorityServers; private List<List<String>> _priorityServers;
private final List<UpdateListener> _listeners; private final List<UpdateListener> _listeners;
private int _queryFrequency; private int _queryFrequency;
private int _concurringServers; private int _concurringServers;
@ -33,11 +34,12 @@ public class RouterTimestamper extends Timestamper {
private boolean _wellSynced; private boolean _wellSynced;
private volatile boolean _isRunning; private volatile boolean _isRunning;
private Thread _timestamperThread; private Thread _timestamperThread;
private final Zones _zones;
private static final int MIN_QUERY_FREQUENCY = 5*60*1000; private static final int MIN_QUERY_FREQUENCY = 5*60*1000;
private static final int DEFAULT_QUERY_FREQUENCY = 11*60*1000; private static final int DEFAULT_QUERY_FREQUENCY = 11*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 String DEFAULT_DISABLED = "true"; private static final boolean 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;
private static final int MAX_CONSECUTIVE_FAILS = 10; private static final int MAX_CONSECUTIVE_FAILS = 10;
@ -51,13 +53,23 @@ public class RouterTimestamper extends Timestamper {
/** 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;
/**
* Does not start. Caller MUST call startTimestamper()
*/
public RouterTimestamper(I2PAppContext ctx) { public RouterTimestamper(I2PAppContext ctx) {
this(ctx, null, true); this(ctx, null, true);
} }
/**
* Does not start. Caller MUST call startTimestamper()
*/
public RouterTimestamper(I2PAppContext ctx, UpdateListener lsnr) { public RouterTimestamper(I2PAppContext ctx, UpdateListener lsnr) {
this(ctx, lsnr, true); this(ctx, lsnr, true);
} }
/**
* Does not start. Caller MUST call startTimestamper()
*/
public RouterTimestamper(I2PAppContext ctx, UpdateListener lsnr, boolean daemon) { public RouterTimestamper(I2PAppContext ctx, UpdateListener lsnr, boolean daemon) {
super(); super();
// moved here to prevent problems with synchronized statements. // moved here to prevent problems with synchronized statements.
@ -71,15 +83,17 @@ public class RouterTimestamper extends Timestamper {
// This means we no longer check every 5 minutes to see if we got enabled, // This means we no longer check every 5 minutes to see if we got enabled,
// so the property must be set at startup. // so the property must be set at startup.
// We still need to be instantiated since the router calls clock().getTimestamper().waitForInitialization() // We still need to be instantiated since the router calls clock().getTimestamper().waitForInitialization()
String disabled = ctx.getProperty(PROP_DISABLED, DEFAULT_DISABLED); _disabled = ctx.getProperty(PROP_DISABLED, DEFAULT_DISABLED);
if (Boolean.parseBoolean(disabled)) { if (_disabled) {
_initialized = true; _initialized = true;
_zones = null;
System.out.println("Warning: NTP is disabled");
return; return;
} }
if (lsnr != null) if (lsnr != null)
_listeners.add(lsnr); _listeners.add(lsnr);
_zones = new Zones(ctx);
updateConfig(); updateConfig();
startTimestamper();
} }
public int getServerCount() { public int getServerCount() {
@ -110,7 +124,9 @@ public class RouterTimestamper extends Timestamper {
return _listeners.get(index); return _listeners.get(index);
} }
private void startTimestamper() { public void startTimestamper() {
if (_disabled || _initialized)
return;
_timestamperThread = new I2PThread(this, "Timestamper", _daemon); _timestamperThread = new I2PThread(this, "Timestamper", _daemon);
_timestamperThread.setPriority(I2PThread.MIN_PRIORITY); _timestamperThread.setPriority(I2PThread.MIN_PRIORITY);
_isRunning = true; _isRunning = true;
@ -149,48 +165,72 @@ public class RouterTimestamper extends Timestamper {
@Override @Override
public void run() { public void run() {
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
_log = _context.logManager().getLog(Timestamper.class);
if (_log.shouldLog(Log.INFO))
_log.info("Starting timestamper");
boolean lastFailed = false; boolean lastFailed = false;
try { try {
while (_isRunning) { while (_isRunning) {
// NOTE: _log is null the first time through, to prevent problems and stack overflows
updateConfig(); updateConfig();
if (!_disabled) { if (!_disabled) {
// first the servers for our country, if we know what country we're in... // first the servers for our country and continent, we know what country we're in...
if (_priorityServers != null) { if (_priorityServers != null) {
if (_log.shouldLog(Log.DEBUG)) for (List<String> servers : _priorityServers) {
_log.debug("Querying servers " + _priorityServers); if (_log != null && _log.shouldDebug())
try { _log.debug("Querying servers " + servers);
lastFailed = !queryTime(_priorityServers.toArray(new String[_priorityServers.size()])); try {
} catch (IllegalArgumentException iae) { lastFailed = !queryTime(servers.toArray(new String[servers.size()]));
if ( (!lastFailed) && (_log.shouldLog(Log.WARN)) ) } catch (IllegalArgumentException iae) {
_log.warn("Unable to reach country-specific NTP servers"); if (!lastFailed && _log != null && _log.shouldWarn())
lastFailed = true; _log.warn("Unable to reach any regional NTP servers: " + servers);
lastFailed = true;
}
if (!lastFailed)
break;
} }
} }
// ... and then the global list, if that failed // ... and then the global list, if that failed
if (_priorityServers == null || lastFailed) { if (_priorityServers == null || lastFailed) {
if (_log.shouldLog(Log.DEBUG)) if (_log != null && _log.shouldDebug())
_log.debug("Querying servers " + _servers); _log.debug("Querying servers " + _servers);
try { try {
lastFailed = !queryTime(_servers.toArray(new String[_servers.size()])); lastFailed = !queryTime(_servers.toArray(new String[_servers.size()]));
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
if ( (!_initialized) && (_log.shouldLog(Log.ERROR)) ) {
List<String> all = new ArrayList<String>();
if (_priorityServers != null)
all.addAll(_priorityServers);
all.addAll(_servers);
_log.error("Unable to reach any of the NTP servers " + all + " - network disconnected? Or set time.sntpServerList=myserver1.com,myserver2.com in advanced configuration.");
}
lastFailed = true; lastFailed = true;
} }
} }
} }
_initialized = true; boolean wasInitialized = _initialized;
if (!wasInitialized)
_initialized = true;
synchronized (this) { notifyAll(); } synchronized (this) { notifyAll(); }
if (!wasInitialized) {
// let the log manager get initialized
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
// NOW we set up logging
_log = _context.logManager().getLog(RouterTimestamper.class);
if (lastFailed) {
List<String> all = new ArrayList<String>(9);
if (_priorityServers != null) {
for (List<String> servers : _priorityServers) {
all.addAll(servers);
}
}
all.addAll(_servers);
String msg = "Unable to reach any of the NTP servers " + all +
" - network disconnected? Or set time.sntpServerList=myserver1.com,myserver2.com in advanced configuration.";
_log.logAlways(Log.WARN, msg);
System.out.println("Warning: " + msg);
} else if (_log.shouldDebug()) {
_log.debug("NTP initialization successful");
int i = 1;
if (_priorityServers != null) {
for (List<String> servers : _priorityServers) {
_log.debug("NTP Server list " + (i++) + ": " + servers);
}
}
_log.debug("NTP Server list " + i + ": " + _servers);
}
}
long sleepTime; long sleepTime;
if (lastFailed) { if (lastFailed) {
if (++_consecutiveFails >= MAX_CONSECUTIVE_FAILS) if (++_consecutiveFails >= MAX_CONSECUTIVE_FAILS)
@ -206,8 +246,10 @@ public class RouterTimestamper extends Timestamper {
try { Thread.sleep(sleepTime); } catch (InterruptedException ie) {} try { Thread.sleep(sleepTime); } catch (InterruptedException ie) {}
} }
} catch (Throwable t) { } catch (Throwable t) {
_log.log(Log.CRIT, "Timestamper died!", t);
synchronized (this) { notifyAll(); } synchronized (this) { notifyAll(); }
if (_log != null)
_log.log(Log.CRIT, "Timestamper died!", t);
t.printStackTrace();
} }
} }
@ -232,7 +274,7 @@ public class RouterTimestamper extends Timestamper {
found[i] = delta; found[i] = delta;
if (i == 0) { if (i == 0) {
if (Math.abs(delta) < MAX_VARIANCE) { if (Math.abs(delta) < MAX_VARIANCE) {
if (_log.shouldLog(Log.INFO)) if (_log != null && _log.shouldInfo())
_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 // If less than a half second on the first try, we're in good shape
_wellSynced = Math.abs(delta) < 500; _wellSynced = Math.abs(delta) < 500;
@ -243,7 +285,7 @@ public class RouterTimestamper extends Timestamper {
} }
} else { } else {
if (Math.abs(delta - expectedDelta) > MAX_VARIANCE) { if (Math.abs(delta - expectedDelta) > MAX_VARIANCE) {
if (_log.shouldLog(Log.ERROR)) { if (_log != null && _log.shouldError()) {
StringBuilder err = new StringBuilder(96); StringBuilder err = new StringBuilder(96);
err.append("SNTP client variance exceeded at query ").append(i); err.append("SNTP client variance exceeded at query ").append(i);
err.append(". expected = "); err.append(". expected = ");
@ -260,7 +302,7 @@ public class RouterTimestamper extends Timestamper {
} }
} }
stampTime(now, stratum); stampTime(now, stratum);
if (_log.shouldLog(Log.DEBUG)) { if (_log != null && _log.shouldDebug()) {
StringBuilder buf = new StringBuilder(64); StringBuilder buf = new StringBuilder(64);
buf.append("Deltas: "); buf.append("Deltas: ");
for (int i = 0; i < found.length; i++) for (int i = 0; i < found.length; i++)
@ -280,13 +322,13 @@ public class RouterTimestamper extends Timestamper {
for (UpdateListener lsnr : _listeners) { for (UpdateListener lsnr : _listeners) {
lsnr.setNow(now, stratum); lsnr.setNow(now, stratum);
} }
if (_log.shouldLog(Log.DEBUG)) if (_log != null && _log.shouldDebug())
_log.debug("Stamped the time as " + now + " (delta=" + (now-before) + ")"); _log.debug("Stamped the time as " + now + " (delta=" + (now-before) + ")");
} }
/** /**
* Reload all the config elements from the appContext * Reload all the config elements from the appContext.
* * No logging allowed here
*/ */
private void updateConfig() { private void updateConfig() {
String serverList = _context.getProperty(PROP_SERVER_LIST); String serverList = _context.getProperty(PROP_SERVER_LIST);
@ -298,10 +340,22 @@ public class RouterTimestamper extends Timestamper {
if (country != null) if (country != null)
country = country.toLowerCase(Locale.US); country = country.toLowerCase(Locale.US);
} }
if (country != null && country.length() > 0) { if (country != null && country.length() > 0 &&
_priorityServers = new ArrayList<String>(3); !country.equals("a1") && !country.equals("a2")) {
for (int i = 0; i < 3; i++) _priorityServers = new ArrayList<List<String>>(2);
_priorityServers.add(i + "." + country + ".pool.ntp.org"); List<String> p1 = new ArrayList<String>(3);
for (int i = 0; i < 3; i++) {
p1.add(i + "." + country + ".pool.ntp.org");
}
_priorityServers.add(p1);
String zone = _zones.getZone(country);
if (zone != null) {
List<String> p2 = new ArrayList<String>(3);
for (int i = 0; i < 3; i++) {
p2.add(i + "." + zone + ".pool.ntp.org");
}
_priorityServers.add(p2);
}
} else { } else {
_priorityServers = null; _priorityServers = null;
} }
@ -320,8 +374,7 @@ public class RouterTimestamper extends Timestamper {
_queryFrequency = Math.max(MIN_QUERY_FREQUENCY, _queryFrequency = Math.max(MIN_QUERY_FREQUENCY,
_context.getProperty(PROP_QUERY_FREQUENCY, DEFAULT_QUERY_FREQUENCY)); _context.getProperty(PROP_QUERY_FREQUENCY, DEFAULT_QUERY_FREQUENCY));
String disabled = _context.getProperty(PROP_DISABLED, DEFAULT_DISABLED); _disabled = _context.getProperty(PROP_DISABLED, DEFAULT_DISABLED);
_disabled = Boolean.parseBoolean(disabled);
_concurringServers = Math.min(4, Math.max(1, _concurringServers = Math.min(4, Math.max(1,
_context.getProperty(PROP_CONCURRING_SERVERS, DEFAULT_CONCURRING_SERVERS))); _context.getProperty(PROP_CONCURRING_SERVERS, DEFAULT_CONCURRING_SERVERS)));

View File

@ -0,0 +1,135 @@
package net.i2p.router.time;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.router.transport.GeoIP;
/**
* Country to continent mapping for NTP.
* @since 0.9.20
*/
class Zones {
private final I2PAppContext _context;
// can't log here, called from RouterClock constructor, stack overflow
//private final Log _log;
// lower case country to NTP region
private final Map<String, String> _countryToZone;
// upper case continent to NTP region
private final Map<String, String> _continentToZone;
private static final String CONTINENT_FILE_DEFAULT = "continents.txt";
/**
* ref: http://dev.maxmind.com/geoip/legacy/codes/country_continent/
* ref: http://www.pool.ntp.org/zone/@
*/
private static final String[] ZONES = {
// not an NTP zone
//"--", "anonymous-proxy",
"AF", "africa",
// not an NTP zone
//"AN", "antarctica",
"AS", "asia",
"EU", "europe",
"NA", "north-america",
"OC", "oceania",
"SA", "south-america"
};
/**
* Reads in the file in the constructor,
* so hold onto this.
*/
public Zones(I2PAppContext ctx) {
_context = ctx;
//_log = ctx.logManager().getLog(Zones.class);
_countryToZone = new HashMap<String, String>(256);
_continentToZone = new HashMap<String, String>(8);
for (int i = 0; i < ZONES.length; i += 2) {
_continentToZone.put(ZONES[i], ZONES[i+1]);
}
readContinentFile();
}
/**
* Get the NTP zone for a country
*
* @param country non-null, two letter code, case-independent
* @return lower-case NTP zone, e.g. "africa", or null
*/
public String getZone (String country) {
return _countryToZone.get(country.toLowerCase(Locale.US));
}
/**
* Read in and parse the continent file.
* The file need not be sorted.
*
* Format:
* #comment (# must be in column 1)
* country code,continent code
*
* Example:
* US,NA
*
* Modified from GeoIP.readCountryFile()
* ref: http://dev.maxmind.com/geoip/legacy/codes/country_continent/
*/
private void readContinentFile() {
String geoDir = _context.getProperty(GeoIP.PROP_GEOIP_DIR, GeoIP.GEOIP_DIR_DEFAULT);
File geoFile = new File(geoDir);
if (!geoFile.isAbsolute())
geoFile = new File(_context.getBaseDir(), geoDir);
geoFile = new File(geoFile, CONTINENT_FILE_DEFAULT);
if (!geoFile.exists()) {
//if (_log.shouldWarn())
// _log.warn("Continent file not found: " + geoFile.getAbsolutePath());
return;
}
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(
new FileInputStream(geoFile), "UTF-8"));
String line = null;
while ((line = br.readLine()) != null) {
try {
if (line.charAt(0) == '#')
continue;
String[] s = line.split(",");
String ucContinent = s[1].toUpperCase(Locale.US).trim();
String zone = _continentToZone.get(ucContinent);
if (zone == null)
continue;
String lcCountry = s[0].toLowerCase(Locale.US).trim();
_countryToZone.put(lcCountry, zone);
//if (_log.shouldDebug())
// _log.debug("Country " + lcCountry + " is in " + zone);
} catch (IndexOutOfBoundsException ioobe) {}
}
} catch (IOException ioe) {
System.out.println("Error reading the continent file " + geoFile.getAbsolutePath());
} finally {
if (br != null) try { br.close(); } catch (IOException ioe) {}
}
}
/****
public static void main(String args[]) {
Zones z = new Zones(I2PAppContext.getGlobalContext());
String tests[] = {"us", "US", "nz", "fr", "vU", "br", "cn", "ao", "A1", "foo" };
for (int i = 0; i < tests.length; i++) {
System.out.println(tests[i] + " : " + z.getZone(tests[i]));
}
}
****/
}

View File

@ -73,7 +73,7 @@ public class GeoIP {
static final String PROP_GEOIP_ENABLED = "routerconsole.geoip.enable"; static final String PROP_GEOIP_ENABLED = "routerconsole.geoip.enable";
public static final String PROP_GEOIP_DIR = "geoip.dir"; public static final String PROP_GEOIP_DIR = "geoip.dir";
static final String GEOIP_DIR_DEFAULT = "geoip"; public static final String GEOIP_DIR_DEFAULT = "geoip";
static final String GEOIP_FILE_DEFAULT = "geoip.txt"; static final String GEOIP_FILE_DEFAULT = "geoip.txt";
static final String COUNTRY_FILE_DEFAULT = "countries.txt"; static final String COUNTRY_FILE_DEFAULT = "countries.txt";
public static final String PROP_IP_COUNTRY = "i2np.lastCountry"; public static final String PROP_IP_COUNTRY = "i2np.lastCountry";