forked from I2P_Developers/i2p.i2p
i2ptunnel:
Store configFile path in controller so it doesn't change Simplify assureConfigFile() Sanitize tunnel name when creating config file name Sort config when saving Don't copy config when saving Make shouldMigrate() private Javadocs
This commit is contained in:
@ -51,6 +51,7 @@ import net.i2p.util.SystemVersion;
|
|||||||
public class TunnelController implements Logging {
|
public class TunnelController implements Logging {
|
||||||
private final Log _log;
|
private final Log _log;
|
||||||
private Properties _config;
|
private Properties _config;
|
||||||
|
private File _configFile;
|
||||||
private final I2PTunnel _tunnel;
|
private final I2PTunnel _tunnel;
|
||||||
private final List<String> _messages;
|
private final List<String> _messages;
|
||||||
private List<I2PSession> _sessions;
|
private List<I2PSession> _sessions;
|
||||||
@ -86,6 +87,8 @@ public class TunnelController implements Logging {
|
|||||||
public static final String PROP_TARGET_PORT = "targetPort";
|
public static final String PROP_TARGET_PORT = "targetPort";
|
||||||
public static final String PROP_TYPE = "type";
|
public static final String PROP_TYPE = "type";
|
||||||
public static final String PROP_FILTER = "filterDefinition";
|
public static final String PROP_FILTER = "filterDefinition";
|
||||||
|
/** @since 0.9.42 */
|
||||||
|
public static final String PROP_CONFIG_FILE = "configFile";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* all of these are @since 0.9.33 (moved from TunnelConfig)
|
* all of these are @since 0.9.33 (moved from TunnelConfig)
|
||||||
@ -175,6 +178,9 @@ public class TunnelController implements Logging {
|
|||||||
* the prefix should be used (and, in turn, that prefix should be stripped off
|
* the prefix should be used (and, in turn, that prefix should be stripped off
|
||||||
* before being interpreted by this controller)
|
* before being interpreted by this controller)
|
||||||
*
|
*
|
||||||
|
* If config contains the "configFile" property, it will be set as the config path
|
||||||
|
* and may be retrieved with getConfigFile().
|
||||||
|
*
|
||||||
* Defaults in config properties are not recommended, they may or may not be honored.
|
* Defaults in config properties are not recommended, they may or may not be honored.
|
||||||
*
|
*
|
||||||
* @param config original key=value mapping non-null
|
* @param config original key=value mapping non-null
|
||||||
@ -185,6 +191,14 @@ public class TunnelController implements Logging {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Create a new controller for a tunnel out of the specific config options.
|
||||||
|
* The config may contain a large number of options - only ones that begin in
|
||||||
|
* the prefix should be used (and, in turn, that prefix should be stripped off
|
||||||
|
* before being interpreted by this controller)
|
||||||
|
*
|
||||||
|
* If config contains the "configFile" property, it will be set as the config path
|
||||||
|
* and may be retrieved with getConfigFile().
|
||||||
|
*
|
||||||
* Defaults in config properties are not recommended, they may or may not be honored.
|
* Defaults in config properties are not recommended, they may or may not be honored.
|
||||||
*
|
*
|
||||||
* @param config original key=value mapping non-null
|
* @param config original key=value mapping non-null
|
||||||
@ -806,6 +820,11 @@ public class TunnelController implements Logging {
|
|||||||
Properties oldConfig = _config;
|
Properties oldConfig = _config;
|
||||||
_config = props;
|
_config = props;
|
||||||
|
|
||||||
|
// save the config file this was loaded from, if passed in
|
||||||
|
String cname = _config.getProperty(PROP_CONFIG_FILE);
|
||||||
|
if (cname != null && _configFile == null)
|
||||||
|
_configFile = new File(cname);
|
||||||
|
|
||||||
// Set up some per-type defaults
|
// Set up some per-type defaults
|
||||||
// This really isn't the best spot to do this but for servers in particular,
|
// This really isn't the best spot to do this but for servers in particular,
|
||||||
// it's hard to override settings in the subclass since the session connect
|
// it's hard to override settings in the subclass since the session connect
|
||||||
@ -938,11 +957,25 @@ public class TunnelController implements Logging {
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the config file as passed into constructor via "configFile" property,
|
||||||
|
* or as set later, or null
|
||||||
|
* @since 0.9.42
|
||||||
|
*/
|
||||||
|
public File getConfigFile() { return _configFile; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the config file. Only do this if previously null.
|
||||||
|
* @since 0.9.42
|
||||||
|
*/
|
||||||
|
public void setConfigFile(File file) { _configFile = file; }
|
||||||
|
|
||||||
public String getType() { return _config.getProperty(PROP_TYPE); }
|
public String getType() { return _config.getProperty(PROP_TYPE); }
|
||||||
public String getName() { return _config.getProperty(PROP_NAME); }
|
public String getName() { return _config.getProperty(PROP_NAME); }
|
||||||
public String getDescription() { return _config.getProperty(PROP_DESCR); }
|
public String getDescription() { return _config.getProperty(PROP_DESCR); }
|
||||||
public String getI2CPHost() { return _config.getProperty(PROP_I2CP_HOST); }
|
public String getI2CPHost() { return _config.getProperty(PROP_I2CP_HOST); }
|
||||||
public String getI2CPPort() { return _config.getProperty(PROP_I2CP_PORT); }
|
public String getI2CPPort() { return _config.getProperty(PROP_I2CP_PORT); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Absolute path to filter definition file
|
* Absolute path to filter definition file
|
||||||
* @since 0.9.40
|
* @since 0.9.40
|
||||||
|
@ -285,7 +285,7 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
* @returns true if a migration is relevant to the platform, false if not
|
* @returns true if a migration is relevant to the platform, false if not
|
||||||
* @since 0.9.42
|
* @since 0.9.42
|
||||||
*/
|
*/
|
||||||
public boolean shouldMigrate() {
|
private boolean shouldMigrate() {
|
||||||
try {
|
try {
|
||||||
if (_context.isRouterContext()) {
|
if (_context.isRouterContext()) {
|
||||||
if (!SystemVersion.isAndroid()) {
|
if (!SystemVersion.isAndroid()) {
|
||||||
@ -294,9 +294,7 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,19 +403,15 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
String tname = props.getProperty("name");
|
String tname = props.getProperty("name");
|
||||||
if (tname == null)
|
if (tname == null)
|
||||||
tname = "tunnel";
|
tname = "tunnel";
|
||||||
|
else
|
||||||
|
tname = sanitize(tname);
|
||||||
String name = i + "-" + tname + "-i2ptunnel.config";
|
String name = i + "-" + tname + "-i2ptunnel.config";
|
||||||
if (i < 10)
|
if (i < 10)
|
||||||
name = '0' + name;
|
name = '0' + name;
|
||||||
File f = new File(dir, name);
|
File f = new File(dir, name);
|
||||||
props.setProperty("configFile", f.getAbsolutePath());
|
props.setProperty(TunnelController.PROP_CONFIG_FILE, f.getAbsolutePath());
|
||||||
Properties save = new OrderedProperties();
|
|
||||||
for (Map.Entry<Object, Object> e : props.entrySet()) {
|
|
||||||
String key = (String) e.getKey();
|
|
||||||
String val = (String) e.getValue();
|
|
||||||
save.setProperty(key, val);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
DataHelper.storeProps(save, f);
|
DataHelper.storeProps(props, f);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
if (_log.shouldLog(Log.ERROR))
|
if (_log.shouldLog(Log.ERROR))
|
||||||
_log.error("Error migrating the i2ptunnel configuration to " + f, ioe);
|
_log.error("Error migrating the i2ptunnel configuration to " + f, ioe);
|
||||||
@ -674,7 +668,8 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the configuration of all known tunnels to the given file
|
* Save the configuration of all known tunnels to the given file.
|
||||||
|
* Side effect: for split config, sets "confFile" property to absolute path.
|
||||||
* @since 0.9.42
|
* @since 0.9.42
|
||||||
*/
|
*/
|
||||||
private synchronized void saveConfig(File cfgFile) throws IOException {
|
private synchronized void saveConfig(File cfgFile) throws IOException {
|
||||||
@ -690,7 +685,7 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
map.putAll(cur);
|
map.putAll(cur);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
map.setProperty("configFile", cfgFile.getAbsolutePath());
|
map.setProperty(TunnelController.PROP_CONFIG_FILE, cfgFile.getAbsolutePath());
|
||||||
} finally {
|
} finally {
|
||||||
_controllersLock.readLock().unlock();
|
_controllersLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@ -698,7 +693,8 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the configuration of this tunnel only, may be new
|
* Save the configuration of this tunnel only, may be new.
|
||||||
|
* Side effect: for split config, sets "confFile" property to absolute path.
|
||||||
* @since 0.9.42
|
* @since 0.9.42
|
||||||
*/
|
*/
|
||||||
public synchronized void saveConfig(TunnelController tc) throws IOException {
|
public synchronized void saveConfig(TunnelController tc) throws IOException {
|
||||||
@ -708,9 +704,10 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
}
|
}
|
||||||
if (_log.shouldInfo())
|
if (_log.shouldInfo())
|
||||||
_log.info("Saving tunnel configuration for " + tc);
|
_log.info("Saving tunnel configuration for " + tc);
|
||||||
Properties inputController = tc.getConfig("");
|
Properties inputController = new OrderedProperties();
|
||||||
|
inputController.putAll(tc.getConfig(""));
|
||||||
File cfgFile = assureConfigFile(tc);
|
File cfgFile = assureConfigFile(tc);
|
||||||
inputController.setProperty("configFile", cfgFile.getAbsolutePath());
|
inputController.setProperty(TunnelController.PROP_CONFIG_FILE, cfgFile.getAbsolutePath());
|
||||||
DataHelper.storeProps(inputController, cfgFile);
|
DataHelper.storeProps(inputController, cfgFile);
|
||||||
tc.setConfig(inputController, "");
|
tc.setConfig(inputController, "");
|
||||||
}
|
}
|
||||||
@ -729,6 +726,32 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** From i2psnark Storage.java */
|
||||||
|
private static final char[] ILLEGAL = new char[] {
|
||||||
|
'<', '>', ':', '"', '/', '\\', '|', '?', '*',
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
|
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
|
0x7f,
|
||||||
|
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||||
|
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||||
|
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||||
|
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||||
|
// unicode newlines
|
||||||
|
0x2028, 0x2029
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace problematic characters in file name
|
||||||
|
* @since 0.9.42
|
||||||
|
*/
|
||||||
|
private static String sanitize(String rv) {
|
||||||
|
for (int i = 0; i < ILLEGAL.length; i++) {
|
||||||
|
if (rv.indexOf(ILLEGAL[i]) >= 0)
|
||||||
|
rv = rv.replace(ILLEGAL[i], '_');
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the config File associated with a TunnelController or a default
|
* return the config File associated with a TunnelController or a default
|
||||||
* File based on the tunnel name.
|
* File based on the tunnel name.
|
||||||
@ -737,26 +760,23 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
* @return the File ready for use
|
* @return the File ready for use
|
||||||
*/
|
*/
|
||||||
private synchronized File assureConfigFile(TunnelController tc) throws IOException {
|
private synchronized File assureConfigFile(TunnelController tc) throws IOException {
|
||||||
|
File file = tc.getConfigFile();
|
||||||
|
if (file != null)
|
||||||
|
return file;
|
||||||
Properties inputController = tc.getConfig("");
|
Properties inputController = tc.getConfig("");
|
||||||
String configFileName = inputController.getProperty("configFile");
|
|
||||||
if (configFileName == null) {
|
|
||||||
if (_log.shouldLog(Log.WARN))
|
|
||||||
_log.warn("configFile property not found");
|
|
||||||
String fileName = inputController.getProperty("name");
|
String fileName = inputController.getProperty("name");
|
||||||
if (fileName == null)
|
if (fileName == null)
|
||||||
fileName = "New Tunnel";
|
fileName = "New Tunnel";
|
||||||
configFileName = _controllers.size() + "-" + fileName + "-i2ptunnel.config";
|
else
|
||||||
|
fileName = sanitize(fileName);
|
||||||
|
String configFileName = _controllers.size() + "-" + fileName + "-i2ptunnel.config";
|
||||||
if (_controllers.size() < 10)
|
if (_controllers.size() < 10)
|
||||||
configFileName = '0' + configFileName;
|
configFileName = '0' + configFileName;
|
||||||
}
|
|
||||||
|
|
||||||
File file = new File(configFileName);
|
|
||||||
if (!file.isAbsolute()) {
|
|
||||||
File folder = new File(_configDirectory);
|
File folder = new File(_configDirectory);
|
||||||
if (!folder.isAbsolute())
|
if (!folder.isAbsolute())
|
||||||
folder = new File(_context.getConfigDir(), _configDirectory);
|
folder = new File(_context.getConfigDir(), _configDirectory);
|
||||||
file = new File(folder, configFileName);
|
file = new File(folder, configFileName);
|
||||||
}
|
tc.setConfigFile(file);
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,7 +808,8 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load up the config data from either type of config file automatically
|
* Load up the config data from either type of config file automatically.
|
||||||
|
* Side effect: for split config, sets "confFile" property to absolute path.
|
||||||
*
|
*
|
||||||
* @return non-null, properties loaded, one for each tunnel
|
* @return non-null, properties loaded, one for each tunnel
|
||||||
* @throws IOException if unable to load from file
|
* @throws IOException if unable to load from file
|
||||||
@ -806,7 +827,7 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Found split config file " +key+ cfgFile.toString());
|
_log.warn("Found split config file " +key+ cfgFile.toString());
|
||||||
List<Properties> rv = new ArrayList<Properties>(1);
|
List<Properties> rv = new ArrayList<Properties>(1);
|
||||||
config.setProperty("configFile", cfgFile.getAbsolutePath());
|
config.setProperty(TunnelController.PROP_CONFIG_FILE, cfgFile.getAbsolutePath());
|
||||||
rv.add(config);
|
rv.add(config);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -827,7 +848,7 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
String prefix = PREFIX + i + ".";
|
String prefix = PREFIX + i + ".";
|
||||||
Properties p = new Properties();
|
Properties p = new OrderedProperties();
|
||||||
for (Map.Entry<Object, Object> e : config.entrySet()) {
|
for (Map.Entry<Object, Object> e : config.entrySet()) {
|
||||||
String key = (String) e.getKey();
|
String key = (String) e.getKey();
|
||||||
if (key.startsWith(prefix)) {
|
if (key.startsWith(prefix)) {
|
||||||
@ -838,7 +859,6 @@ public class TunnelControllerGroup implements ClientApp {
|
|||||||
}
|
}
|
||||||
if (p.isEmpty())
|
if (p.isEmpty())
|
||||||
break;
|
break;
|
||||||
p.setProperty("configFile", cfgFile);
|
|
||||||
rv.add(p);
|
rv.add(p);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,6 @@ public class GeneralHelper {
|
|||||||
public static List<String> saveTunnel(
|
public static List<String> saveTunnel(
|
||||||
I2PAppContext context, TunnelControllerGroup tcg, int tunnel, TunnelConfig config) {
|
I2PAppContext context, TunnelControllerGroup tcg, int tunnel, TunnelConfig config) {
|
||||||
List<String> msgs = updateTunnelConfig(tcg, tunnel, config);
|
List<String> msgs = updateTunnelConfig(tcg, tunnel, config);
|
||||||
///////////////
|
|
||||||
msgs.addAll(saveConfig(context, tcg, tunnel));
|
msgs.addAll(saveConfig(context, tcg, tunnel));
|
||||||
return msgs;
|
return msgs;
|
||||||
}
|
}
|
||||||
@ -233,7 +232,6 @@ public class GeneralHelper {
|
|||||||
return msgs;
|
return msgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////
|
|
||||||
msgs = tcg.removeController(cur);
|
msgs = tcg.removeController(cur);
|
||||||
try {
|
try {
|
||||||
tcg.removeConfig(cur);
|
tcg.removeConfig(cur);
|
||||||
|
Reference in New Issue
Block a user