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