forked from I2P_Developers/i2p.i2p
* Router:
- Remove global lock on accessing config - Add global lock on reading/writing config file
This commit is contained in:
@ -19,10 +19,12 @@ import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
import net.i2p.crypto.DHSessionKeyBuilder;
|
||||
@ -57,7 +59,7 @@ import net.i2p.util.SimpleTimer;
|
||||
public class Router {
|
||||
private Log _log;
|
||||
private RouterContext _context;
|
||||
private final Properties _config;
|
||||
private final Map<String, String> _config;
|
||||
/** full path */
|
||||
private String _configFilename;
|
||||
private RouterInfo _routerInfo;
|
||||
@ -120,7 +122,7 @@ public class Router {
|
||||
public Router(String configFilename) { this(configFilename, null); }
|
||||
public Router(String configFilename, Properties envProps) {
|
||||
_gracefulExitCode = -1;
|
||||
_config = new Properties();
|
||||
_config = new ConcurrentHashMap();
|
||||
|
||||
if (configFilename == null) {
|
||||
if (envProps != null) {
|
||||
@ -168,15 +170,9 @@ public class Router {
|
||||
|
||||
readConfig();
|
||||
|
||||
if (envProps == null) {
|
||||
envProps = _config;
|
||||
} else {
|
||||
for (Iterator iter = _config.keySet().iterator(); iter.hasNext(); ) {
|
||||
String k = (String)iter.next();
|
||||
String v = _config.getProperty(k);
|
||||
envProps.setProperty(k, v);
|
||||
}
|
||||
}
|
||||
if (envProps == null)
|
||||
envProps = new Properties();
|
||||
envProps.putAll(_config);
|
||||
|
||||
// This doesn't work, guess it has to be in the static block above?
|
||||
// if (Boolean.valueOf(envProps.getProperty("router.disableIPv6")).booleanValue())
|
||||
@ -203,12 +199,12 @@ public class Router {
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
if (_config.getProperty("router.firstVersion") == null) {
|
||||
if (_config.get("router.firstVersion") == null) {
|
||||
// These may be useful someday. First added in 0.8.2
|
||||
_config.setProperty("router.firstVersion", RouterVersion.VERSION);
|
||||
_config.put("router.firstVersion", RouterVersion.VERSION);
|
||||
String now = Long.toString(System.currentTimeMillis());
|
||||
_config.setProperty("router.firstInstalled", now);
|
||||
_config.setProperty("router.updateLastInstalled", now);
|
||||
_config.put("router.firstInstalled", now);
|
||||
_config.put("router.updateLastInstalled", now);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
@ -285,30 +281,20 @@ public class Router {
|
||||
public void setConfigFilename(String filename) { _configFilename = filename; }
|
||||
|
||||
public String getConfigSetting(String name) {
|
||||
synchronized (_config) {
|
||||
return _config.getProperty(name);
|
||||
}
|
||||
return _config.get(name);
|
||||
}
|
||||
public void setConfigSetting(String name, String value) {
|
||||
synchronized (_config) {
|
||||
_config.setProperty(name, value);
|
||||
}
|
||||
_config.put(name, value);
|
||||
}
|
||||
public void removeConfigSetting(String name) {
|
||||
synchronized (_config) {
|
||||
_config.remove(name);
|
||||
}
|
||||
}
|
||||
public Set getConfigSettings() {
|
||||
synchronized (_config) {
|
||||
return new HashSet(_config.keySet());
|
||||
}
|
||||
}
|
||||
public Properties getConfigMap() {
|
||||
Properties rv = new Properties();
|
||||
synchronized (_config) {
|
||||
rv.putAll(_config);
|
||||
}
|
||||
rv.putAll(_config);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -377,14 +363,19 @@ public class Router {
|
||||
_context.jobQueue().addJob(new StartupJob(_context));
|
||||
}
|
||||
|
||||
public void readConfig() {
|
||||
/**
|
||||
* This updates the config with all settings found in the file.
|
||||
* It does not clear the config first, so settings not found in
|
||||
* the file will remain in the config.
|
||||
*
|
||||
* This is synchronized with saveConfig()
|
||||
*/
|
||||
public synchronized void readConfig() {
|
||||
String f = getConfigFilename();
|
||||
Properties config = getConfig(_context, f);
|
||||
for (Iterator iter = config.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
String val = config.getProperty(name);
|
||||
setConfigSetting(name, val);
|
||||
}
|
||||
// to avoid compiler errror
|
||||
Map foo = _config;
|
||||
foo.putAll(config);
|
||||
}
|
||||
|
||||
/** this does not use ctx.getConfigDir(), must provide a full path in filename */
|
||||
@ -988,7 +979,7 @@ public class Router {
|
||||
*/
|
||||
public void shutdownGracefully(int exitCode) {
|
||||
_gracefulExitCode = exitCode;
|
||||
_config.setProperty(PROP_SHUTDOWN_IN_PROGRESS, "true");
|
||||
_config.put(PROP_SHUTDOWN_IN_PROGRESS, "true");
|
||||
synchronized (_gracefulShutdownDetector) {
|
||||
_gracefulShutdownDetector.notifyAll();
|
||||
}
|
||||
@ -1010,7 +1001,7 @@ public class Router {
|
||||
*/
|
||||
public int scheduledGracefulExitCode() { return _gracefulExitCode; }
|
||||
public boolean gracefulShutdownInProgress() {
|
||||
return (null != _config.getProperty(PROP_SHUTDOWN_IN_PROGRESS));
|
||||
return (null != _config.get(PROP_SHUTDOWN_IN_PROGRESS));
|
||||
}
|
||||
/** How long until the graceful shutdown will kill us? */
|
||||
public long getShutdownTimeRemaining() {
|
||||
@ -1033,7 +1024,7 @@ public class Router {
|
||||
private class GracefulShutdown implements Runnable {
|
||||
public void run() {
|
||||
while (true) {
|
||||
boolean shutdown = (null != _config.getProperty(PROP_SHUTDOWN_IN_PROGRESS));
|
||||
boolean shutdown = (null != _config.get(PROP_SHUTDOWN_IN_PROGRESS));
|
||||
if (shutdown) {
|
||||
if (_gracefulExitCode == EXIT_HARD || _gracefulExitCode == EXIT_HARD_RESTART ||
|
||||
_context.tunnelManager().getParticipatingCount() <= 0) {
|
||||
@ -1077,26 +1068,24 @@ public class Router {
|
||||
* this does escape the \r or \n that are unescaped in DataHelper.loadProps().
|
||||
* Note that the escaping of \r or \n was probably a mistake and should be taken out.
|
||||
*
|
||||
* FIXME Synchronize!!
|
||||
* Synchronized with file read in getConfig()
|
||||
*/
|
||||
public boolean saveConfig() {
|
||||
public synchronized boolean saveConfig() {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new SecureFileOutputStream(_configFilename);
|
||||
StringBuilder buf = new StringBuilder(8*1024);
|
||||
buf.append("# NOTE: This I2P config file must use UTF-8 encoding\n");
|
||||
synchronized (_config) {
|
||||
TreeSet ordered = new TreeSet(_config.keySet());
|
||||
for (Iterator iter = ordered.iterator() ; iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = _config.getProperty(key);
|
||||
TreeSet ordered = new TreeSet(_config.keySet());
|
||||
for (Iterator iter = ordered.iterator() ; iter.hasNext(); ) {
|
||||
String key = (String)iter.next();
|
||||
String val = _config.get(key);
|
||||
// Escape line breaks before saving.
|
||||
// Remember: "\" needs escaping both for regex and string.
|
||||
// NOOO - see comments in DataHelper
|
||||
//val = val.replaceAll("\\r","\\\\r");
|
||||
//val = val.replaceAll("\\n","\\\\n");
|
||||
buf.append(key).append('=').append(val).append('\n');
|
||||
}
|
||||
buf.append(key).append('=').append(val).append('\n');
|
||||
}
|
||||
fos.write(buf.toString().getBytes("UTF-8"));
|
||||
} catch (IOException ioe) {
|
||||
@ -1193,7 +1182,7 @@ public class Router {
|
||||
}
|
||||
if (ok) {
|
||||
// This may be useful someday. First added in 0.8.2
|
||||
_config.setProperty("router.updateLastInstalled", "" + System.currentTimeMillis());
|
||||
_config.put("router.updateLastInstalled", "" + System.currentTimeMillis());
|
||||
saveConfig();
|
||||
boolean deleted = updateFile.delete();
|
||||
if (!deleted) {
|
||||
|
Reference in New Issue
Block a user