Finished implementation of UPNP:

*) will try other ports if YaCy standard ports are not available
*) distinguish between internal and external port (not sure if this
works 100%)

Still to add: propery in config to enter own external port (in case of
manually configured NAT)
pull/1/head
Marc Nause 10 years ago
parent d0358e568b
commit 1e6e69bc40

@ -100,7 +100,7 @@ public class ConfigBasic {
port = post.getLong("port", 8090); port = post.getLong("port", 8090);
ssl = post.getBoolean("withssl"); ssl = post.getBoolean("withssl");
} else { } else {
port = env.getConfigLong("port", 8090); //this allows a low port, but it will only get one, if the user edits the config himself. port = env.getLocalPort("port", 8090); //this allows a low port, but it will only get one, if the user edits the config himself.
ssl = env.getConfigBool("server.https", false); ssl = env.getConfigBool("server.https", false);
} }
if (ssl) prop.put("withsslenabled_sslport",env.getHttpServer().getSslPort()); if (ssl) prop.put("withsslenabled_sslport",env.getHttpServer().getSslPort());
@ -266,7 +266,7 @@ public class ConfigBasic {
// set default values // set default values
prop.putHTML("defaultName", sb.peers.mySeed().getName()); prop.putHTML("defaultName", sb.peers.mySeed().getName());
prop.putHTML("defaultPort", env.getConfig("port", "8090")); prop.put("defaultPort", env.getLocalPort("port", 8090));
prop.put("withsslenabled", env.getConfigBool("server.https", false) ? 1 : 0); prop.put("withsslenabled", env.getConfigBool("server.https", false) ? 1 : 0);
lang = env.getConfig("locale.language", "default"); // re-assign lang, may have changed lang = env.getConfig("locale.language", "default"); // re-assign lang, may have changed
prop.put("lang_de", "0"); prop.put("lang_de", "0");

@ -221,7 +221,7 @@ public class ConfigPortal {
String myaddress = (sb.peers == null) ? null : sb.peers.mySeed() == null ? null : sb.peers.mySeed().getPublicAddress(); String myaddress = (sb.peers == null) ? null : sb.peers.mySeed() == null ? null : sb.peers.mySeed().getPublicAddress();
if (myaddress == null) { if (myaddress == null) {
myaddress = "localhost:" + sb.getConfig("port", "8090"); myaddress = "localhost:" + sb.getLocalPort("port", 8090);
} }
prop.put("myaddress", myaddress); prop.put("myaddress", myaddress);
return prop; return prop;

@ -35,7 +35,7 @@ public class ConfigSearchBox {
final Switchboard sb = (Switchboard) env; final Switchboard sb = (Switchboard) env;
String myaddress = sb.peers.mySeed().getPublicAddress(); String myaddress = sb.peers.mySeed().getPublicAddress();
if (myaddress == null) myaddress = "localhost:" + sb.getConfig("port", "8090"); if (myaddress == null) myaddress = "localhost:" + sb.getLocalPort("port", 8090);
prop.put("myaddress", myaddress); prop.put("myaddress", myaddress);
return prop; return prop;
} }

@ -214,7 +214,7 @@ public class CrawlStartScanner_p
path += "&crawlingURL=" + url.toNormalform(true); path += "&crawlingURL=" + url.toNormalform(true);
WorkTables.execAPICall( WorkTables.execAPICall(
Domains.LOCALHOST, Domains.LOCALHOST,
(int) sb.getConfigLong("port", 8090), sb.getLocalPort("port", 8090),
path, path,
pk, pk,
sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"), sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"),
@ -261,7 +261,7 @@ public class CrawlStartScanner_p
path += "&crawlingURL=" + urlString; path += "&crawlingURL=" + urlString;
WorkTables.execAPICall( WorkTables.execAPICall(
Domains.LOCALHOST, Domains.LOCALHOST,
(int) sb.getConfigLong("port", 8090), sb.getLocalPort("port", 8090),
path, path,
u.hash(), u.hash(),
sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"), sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"),

@ -39,7 +39,7 @@ public class Load_MediawikiWiki {
// define visible variables // define visible variables
String a = sb.peers.mySeed().getPublicAddress(); String a = sb.peers.mySeed().getPublicAddress();
if (a == null) a = "localhost:" + sb.getConfig("port", "8090"); if (a == null) a = "localhost:" + sb.getLocalPort("port", 8090);
final boolean intranet = sb.getConfig(SwitchboardConstants.NETWORK_NAME, "").equals("intranet"); final boolean intranet = sb.getConfig(SwitchboardConstants.NETWORK_NAME, "").equals("intranet");
final String repository = "http://" + a + "/repository/"; final String repository = "http://" + a + "/repository/";
prop.put("starturl", (intranet) ? repository : "http://"); prop.put("starturl", (intranet) ? repository : "http://");

@ -39,7 +39,7 @@ public class Load_PHPBB3 {
// define visible variables // define visible variables
String a = sb.peers.mySeed().getPublicAddress(); String a = sb.peers.mySeed().getPublicAddress();
if (a == null) a = "localhost:" + sb.getConfig("port", "8090"); if (a == null) a = "localhost:" + sb.getLocalPort("port", 8090);
final boolean intranet = sb.getConfig(SwitchboardConstants.NETWORK_NAME, "").equals("intranet"); final boolean intranet = sb.getConfig(SwitchboardConstants.NETWORK_NAME, "").equals("intranet");
final String repository = "http://" + a + "/repository/"; final String repository = "http://" + a + "/repository/";
prop.put("starturl", (intranet) ? repository : "http://"); prop.put("starturl", (intranet) ? repository : "http://");

@ -99,7 +99,7 @@ public class SettingsAck_p {
/* /*
* display port info * display port info
*/ */
prop.putHTML("info_port", env.getConfig("port", "8090")); prop.put("info_port", env.getLocalPort("port", 8090));
prop.put("info_restart", "0"); prop.put("info_restart", "0");
// read and process data // read and process data
@ -483,7 +483,7 @@ public class SettingsAck_p {
// change https port // change https port
if (post.containsKey("port.ssl")) { if (post.containsKey("port.ssl")) {
int port = post.getInt("port.ssl", 8443); int port = post.getInt("port.ssl", 8443);
if (port > 0 && port != env.getConfigInt("port", 8090)) { if (port > 0 && port != env.getLocalPort("port", 8090)) {
env.setConfig("port.ssl", port); env.setConfig("port.ssl", port);
} }
prop.put("info_port.ssl", port); prop.put("info_port.ssl", port);

@ -73,7 +73,7 @@ public final class Settings_p {
prop.put("settingsTables", ""); prop.put("settingsTables", "");
} }
prop.put("port", env.getConfig("port", "8090")); prop.put("port", env.getLocalPort("port", 8090));
prop.putHTML("peerName", sb.peers.mySeed().getName()); prop.putHTML("peerName", sb.peers.mySeed().getName());
prop.putHTML("staticIP", env.getConfig("staticIP", "")); prop.putHTML("staticIP", env.getConfig("staticIP", ""));

@ -206,7 +206,7 @@ public class Table_API_p {
} }
// now call the api URLs and store the result status // now call the api URLs and store the result status
final Map<String, Integer> l = sb.tables.execAPICalls(Domains.LOCALHOST, (int) sb.getConfigLong("port", 8090), pks, sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"), sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_B64MD5, "")); final Map<String, Integer> l = sb.tables.execAPICalls(Domains.LOCALHOST, sb.getLocalPort("port", 8090), pks, sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"), sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_B64MD5, ""));
// construct result table // construct result table
prop.put("showexec", l.isEmpty() ? 0 : 1); prop.put("showexec", l.isEmpty() ? 0 : 1);
@ -297,7 +297,7 @@ public class Table_API_p {
} else { } else {
prop.put("showtable_list_" + count + "_isCrawlerStart", 0); prop.put("showtable_list_" + count + "_isCrawlerStart", 0);
} }
prop.putHTML("showtable_list_" + count + "_inline_url", "http://" + sb.myPublicIP() + ":" + sb.getConfig("port", "8090") + UTF8.String(row.get(WorkTables.TABLE_API_COL_URL))); prop.putHTML("showtable_list_" + count + "_inline_url", "http://" + sb.myPublicIP() + ":" + sb.getPublicPort("port", 8090) + UTF8.String(row.get(WorkTables.TABLE_API_COL_URL)));
prop.put("showtable_list_" + count + "_scheduler_inline", inline ? "true" : "false"); prop.put("showtable_list_" + count + "_scheduler_inline", inline ? "true" : "false");
prop.put("showtable_list_" + count + "_scheduler_filter", typefilter.pattern()); prop.put("showtable_list_" + count + "_scheduler_filter", typefilter.pattern());
prop.put("showtable_list_" + count + "_scheduler_query", query.pattern()); prop.put("showtable_list_" + count + "_scheduler_query", query.pattern());

@ -122,7 +122,7 @@ public class push_p {
sb.indexingDocumentProcessor.enQueue(in); sb.indexingDocumentProcessor.enQueue(in);
} }
prop.put("mode_results_" + i + "_success", "1"); prop.put("mode_results_" + i + "_success", "1");
prop.put("mode_results_" + i + "_success_message", "http://" + Domains.myPublicLocalIP().getHostAddress() + ":" + sb.getConfigInt("port", 8090) + "/solr/select?q=sku:%22" + u + "%22"); prop.put("mode_results_" + i + "_success_message", "http://" + Domains.myPublicLocalIP().getHostAddress() + ":" + sb.getLocalPort("port", 8090) + "/solr/select?q=sku:%22" + u + "%22");
countsuccess++; countsuccess++;
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
e.printStackTrace(); e.printStackTrace();

@ -40,7 +40,7 @@ public class opensearchdescription {
if (env.getConfigBool(SwitchboardConstants.GREETING_NETWORK_NAME, false)) promoteSearchPageGreeting = env.getConfig("network.unit.description", ""); if (env.getConfigBool(SwitchboardConstants.GREETING_NETWORK_NAME, false)) promoteSearchPageGreeting = env.getConfig("network.unit.description", "");
String thisaddress = header.get("Host", Domains.LOCALHOST); String thisaddress = header.get("Host", Domains.LOCALHOST);
if (thisaddress.indexOf(':',0) == -1) thisaddress += ":" + env.getConfig("port", "8090"); if (thisaddress.indexOf(':',0) == -1) thisaddress += ":" + env.getLocalPort("port", 8090);
String thisprotocol = env.getConfigBool("server.https", false) ? "https" : "http"; String thisprotocol = env.getConfigBool("server.https", false) ? "https" : "http";
final serverObjects prop = new serverObjects(); final serverObjects prop = new serverObjects();

@ -146,7 +146,7 @@ public class yacysearch {
// adding some additional properties needed for the rss feed // adding some additional properties needed for the rss feed
String hostName = header.get("Host", Domains.LOCALHOST); String hostName = header.get("Host", Domains.LOCALHOST);
if ( hostName.indexOf(':', 0) == -1 ) { if ( hostName.indexOf(':', 0) == -1 ) {
hostName += ":" + env.getConfig("port", "8090"); hostName += ":" + env.getLocalPort("port", 8090);
} }
prop.put("searchBaseURL", "http://" + hostName + "/yacysearch.html"); prop.put("searchBaseURL", "http://" + hostName + "/yacysearch.html");
prop.put("rssYacyImageURL", "http://" + hostName + "/env/grafics/yacy.png"); prop.put("rssYacyImageURL", "http://" + hostName + "/env/grafics/yacy.png");
@ -880,7 +880,7 @@ public class yacysearch {
// hostname and port (assume locahost if nothing helps) // hostname and port (assume locahost if nothing helps)
final String hostIP = sb.peers.mySeed().getIP(); final String hostIP = sb.peers.mySeed().getIP();
prop.put("myhost", hostIP != null ? hostIP : Domains.LOCALHOST); prop.put("myhost", hostIP != null ? hostIP : Domains.LOCALHOST);
prop.put("myport", sb.getConfig("port", "8090")); prop.put("myport", Domains.LOCALHOST.equals(hostIP) ? sb.getLocalPort("port", 8090) : sb.getPublicPort("port", 8090));
// return rewrite properties // return rewrite properties
return prop; return prop;

@ -91,7 +91,7 @@ public class yacysearch_location {
if (query.length() > 0 && (metatag || search_title || search_publisher || search_creator || search_subject)) try { if (query.length() > 0 && (metatag || search_title || search_publisher || search_creator || search_subject)) try {
// get a queue of search results // get a queue of search results
final String rssSearchServiceURL = "http://127.0.0.1:" + sb.getConfig("port", "8090") + "/yacysearch.rss"; final String rssSearchServiceURL = "http://127.0.0.1:" + sb.getLocalPort("port", 8090) + "/yacysearch.rss";
final BlockingQueue<RSSMessage> results = new LinkedBlockingQueue<RSSMessage>(); final BlockingQueue<RSSMessage> results = new LinkedBlockingQueue<RSSMessage>();
SRURSSConnector.searchSRURSS(results, rssSearchServiceURL, lon == 0.0d && lat == 0.0d ? query : query + " /radius/" + lat + "/" + lon + "/" + radius, maximumTime, Integer.MAX_VALUE, null, false, ClientIdentification.yacyInternetCrawlerAgent); SRURSSConnector.searchSRURSS(results, rssSearchServiceURL, lon == 0.0d && lat == 0.0d ? query : query + " /radius/" + lat + "/" + lon + "/" + radius, maximumTime, Integer.MAX_VALUE, null, false, ClientIdentification.yacyInternetCrawlerAgent);
@ -121,7 +121,7 @@ public class yacysearch_location {
String promoteSearchPageGreeting = env.getConfig(SwitchboardConstants.GREETING, ""); String promoteSearchPageGreeting = env.getConfig(SwitchboardConstants.GREETING, "");
if (env.getConfigBool(SwitchboardConstants.GREETING_NETWORK_NAME, false)) promoteSearchPageGreeting = env.getConfig("network.unit.description", ""); if (env.getConfigBool(SwitchboardConstants.GREETING_NETWORK_NAME, false)) promoteSearchPageGreeting = env.getConfig("network.unit.description", "");
String hostName = header.get("Host", Domains.LOCALHOST); String hostName = header.get("Host", Domains.LOCALHOST);
if (hostName.indexOf(':',0) == -1) hostName += ":" + env.getConfig("port", "8090"); if (hostName.indexOf(':',0) == -1) hostName += ":" + env.getLocalPort("port", "8090");
final String originalquerystring = (post == null) ? "" : post.get("query", post.get("search", "")).trim(); // SRU compliance final String originalquerystring = (post == null) ? "" : post.get("query", post.get("search", "")).trim(); // SRU compliance
final boolean global = post.get("kml_resource", "local").equals("global"); final boolean global = post.get("kml_resource", "local").equals("global");

@ -239,8 +239,8 @@ public final class Tray {
} }
private String readyMessage() { private String readyMessage() {
if (deutsch) return "YaCy laeuft unter http://localhost:" + sb.getConfig("port", "8090"); if (deutsch) return "YaCy laeuft unter http://localhost:" + sb.getLocalPort("port", 8090);
return "YaCy is running at http://localhost:" + sb.getConfig("port", "8090"); return "YaCy is running at http://localhost:" + sb.getLocalPort("port", 8090);
} }
private String shutdownMessage() { private String shutdownMessage() {

@ -82,7 +82,7 @@ public class Jetty9HttpServerImpl implements YaCyHttpServer {
final SSLContext sslContext = initSslContext(sb); final SSLContext sslContext = initSslContext(sb);
if (sslContext != null) { if (sslContext != null) {
int sslport = sb.getConfigInt("port.ssl", 8443); int sslport = sb.getLocalPort("port.ssl", 8443);
sslContextFactory.setSslContext(sslContext); sslContextFactory.setSslContext(sslContext);
// SSL HTTP Configuration // SSL HTTP Configuration
@ -286,8 +286,8 @@ public class Jetty9HttpServerImpl implements YaCyHttpServer {
} }
try { // reconnect with new settings (instead to stop/start server, just manipulate connectors try { // reconnect with new settings (instead to stop/start server, just manipulate connectors
final Connector[] cons = server.getConnectors(); final Connector[] cons = server.getConnectors();
final int port = Switchboard.getSwitchboard().getConfigInt("port", 8090); final int port = Switchboard.getSwitchboard().getLocalPort("port", 8090);
final int sslport = Switchboard.getSwitchboard().getConfigInt("port.ssl", 8443); final int sslport = Switchboard.getSwitchboard().getLocalPort("port.ssl", 8443);
for (Connector con : cons) { for (Connector con : cons) {
// check http connector // check http connector
if (con.getName().startsWith("httpd") && ((ServerConnector)con).getPort() != port) { if (con.getName().startsWith("httpd") && ((ServerConnector)con).getPort() != port) {

@ -1162,9 +1162,9 @@ public class Seed implements Cloneable, Comparable<Seed>, Comparator<Seed>
final Seed newSeed = new Seed(hashs); final Seed newSeed = new Seed(hashs);
// now calculate other information about the host // now calculate other information about the host
final long port = Switchboard.getSwitchboard().getConfigLong("port", 8090); //get port from config final int port = Switchboard.getSwitchboard().getPublicPort("port", 8090); //get port from config
newSeed.dna.put(Seed.NAME, defaultPeerName() ); newSeed.dna.put(Seed.NAME, defaultPeerName() );
newSeed.dna.put(Seed.PORT, Long.toString(port)); newSeed.dna.put(Seed.PORT, Integer.toString(port));
return newSeed; return newSeed;
} }

@ -958,7 +958,7 @@ public final class SeedDB implements AlternativeDomainNames {
if (this.mySeed == null) initMySeed(); if (this.mySeed == null) initMySeed();
if ((seed == this.mySeed) && (!(seed.isOnline()))) { if ((seed == this.mySeed) && (!(seed.isOnline()))) {
// take local ip instead of external // take local ip instead of external
return Switchboard.getSwitchboard().myPublicIP() + ":" + Switchboard.getSwitchboard().getConfig("port", "8090") + ((subdom == null) ? "" : ("/" + subdom)); return Switchboard.getSwitchboard().myPublicIP() + ":" + Switchboard.getSwitchboard().getLocalPort("port", 8090) + ((subdom == null) ? "" : ("/" + subdom));
} }
return seed.getPublicAddress(seed.getIP()) + ((subdom == null) ? "" : ("/" + subdom)); return seed.getPublicAddress(seed.getIP()) + ((subdom == null) ? "" : ("/" + subdom));
} else { } else {

@ -294,7 +294,7 @@ public final class Switchboard extends serverSwitch {
super(dataPath, appPath, initPath, configPath); super(dataPath, appPath, initPath, configPath);
sb = this; sb = this;
// check if port is already occupied // check if port is already occupied
final int port = getConfigInt("port", 8090); final int port = getLocalPort("port", 8090);
if (TimeoutRequest.ping(Domains.LOCALHOST, port, 500)) { if (TimeoutRequest.ping(Domains.LOCALHOST, port, 500)) {
throw new RuntimeException( throw new RuntimeException(
"a server is already running on the YaCy port " "a server is already running on the YaCy port "
@ -2453,7 +2453,7 @@ public final class Switchboard extends serverSwitch {
startupAction = false; startupAction = false;
// execute api calls // execute api calls
final Map<String, Integer> callResult = this.tables.execAPICalls("localhost", (int) getConfigLong("port", 8090), pks, getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"), getConfig(SwitchboardConstants.ADMIN_ACCOUNT_B64MD5, "")); final Map<String, Integer> callResult = this.tables.execAPICalls("localhost", getLocalPort("port", 8090), pks, getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"), getConfig(SwitchboardConstants.ADMIN_ACCOUNT_B64MD5, ""));
for ( final Map.Entry<String, Integer> call : callResult.entrySet() ) { for ( final Map.Entry<String, Integer> call : callResult.entrySet() ) {
this.log.info("Scheduler executed api call, response " + call.getValue() + ": " + call.getKey()); this.log.info("Scheduler executed api call, response " + call.getValue() + ": " + call.getKey());
} }
@ -3675,7 +3675,7 @@ public final class Switchboard extends serverSwitch {
private static long indeSizeCache = 0; private static long indeSizeCache = 0;
private static long indexSizeTime = 0; private static long indexSizeTime = 0;
public void updateMySeed() { public void updateMySeed() {
this.peers.mySeed().put(Seed.PORT, getConfig("port", "8090")); this.peers.mySeed().put(Seed.PORT, Integer.toString(getPublicPort("port", 8090)));
//the speed of indexing (pages/minute) of the peer //the speed of indexing (pages/minute) of the peer
final long uptime = (System.currentTimeMillis() - this.startupTime) / 1000; final long uptime = (System.currentTimeMillis() - this.startupTime) / 1000;

@ -162,13 +162,13 @@ public final class HTTPDemon {
final InetAddress hostAddress = Domains.dnsResolve(clientIP); final InetAddress hostAddress = Domains.dnsResolve(clientIP);
if (hostAddress == null) { if (hostAddress == null) {
tp.put("host", Domains.myPublicLocalIP().getHostAddress()); tp.put("host", Domains.myPublicLocalIP().getHostAddress());
tp.put("port", switchboard.getConfig("port", "8090")); tp.put("port", switchboard.getLocalPort("port", 8090));
} else if (hostAddress.isSiteLocalAddress() || hostAddress.isLoopbackAddress()) { } else if (hostAddress.isSiteLocalAddress() || hostAddress.isLoopbackAddress()) {
tp.put("host", Domains.myPublicLocalIP().getHostAddress()); tp.put("host", Domains.myPublicLocalIP().getHostAddress());
tp.put("port", switchboard.getConfig("port", "8090")); tp.put("port", switchboard.getLocalPort("port", 8090));
} else { } else {
tp.put("host", switchboard.myPublicIP()); tp.put("host", switchboard.myPublicIP());
tp.put("port", switchboard.getConfig("port", "8090")); tp.put("port", switchboard.getPublicPort("port", 8090));
} }
tp.put("peerName", (switchboard.peers == null) ? "" : switchboard.peers.myName()); tp.put("peerName", (switchboard.peers == null) ? "" : switchboard.peers.myName());

@ -56,8 +56,7 @@ import net.yacy.kelondro.workflow.WorkflowThread;
import net.yacy.peers.Seed; import net.yacy.peers.Seed;
import net.yacy.search.SwitchboardConstants; import net.yacy.search.SwitchboardConstants;
public class serverSwitch public class serverSwitch {
{
// configuration management // configuration management
private final File configFile; private final File configFile;
@ -71,12 +70,11 @@ public class serverSwitch
private final ConcurrentMap<String, String> configRemoved; private final ConcurrentMap<String, String> configRemoved;
private final NavigableMap<String, BusyThread> workerThreads; private final NavigableMap<String, BusyThread> workerThreads;
private YaCyHttpServer httpserver; // implemented HttpServer private YaCyHttpServer httpserver; // implemented HttpServer
private ConcurrentMap<String, Integer> upnpPortMap = new ConcurrentHashMap<>();
private boolean isConnectedViaUpnp;
public serverSwitch( public serverSwitch(final File dataPath, final File appPath,
final File dataPath, final String initPath, final String configPath) {
final File appPath,
final String initPath,
final String configPath) {
// we initialize the switchboard with a property file, // we initialize the switchboard with a property file,
// but maintain these properties then later in a new 'config' file // but maintain these properties then later in a new 'config' file
// to reset all changed configs, the config file must // to reset all changed configs, the config file must
@ -85,22 +83,25 @@ public class serverSwitch
// file name of the config file // file name of the config file
this.dataPath = dataPath; this.dataPath = dataPath;
this.appPath = appPath; this.appPath = appPath;
this.configComment = "This is an automatically generated file, updated by serverAbstractSwitch and initialized by " + initPath; this.configComment = "This is an automatically generated file, updated by serverAbstractSwitch and initialized by "
+ initPath;
final File initFile = new File(appPath, initPath); final File initFile = new File(appPath, initPath);
this.configFile = new File(dataPath, configPath); // propertiesFile(config); this.configFile = new File(dataPath, configPath); // propertiesFile(config);
this.firstInit = !this.configFile.exists(); // this is true if the application was started for the first time this.firstInit = !this.configFile.exists(); // this is true if the
// application was started
// for the first time
new File(this.configFile.getParent()).mkdir(); new File(this.configFile.getParent()).mkdir();
// predefine init's // predefine init's
final ConcurrentMap<String, String> initProps; final ConcurrentMap<String, String> initProps;
if ( initFile.exists() ) { if (initFile.exists()) {
initProps = FileUtils.loadMap(initFile); initProps = FileUtils.loadMap(initFile);
} else { } else {
initProps = new ConcurrentHashMap<String, String>(); initProps = new ConcurrentHashMap<String, String>();
} }
// load config's from last save // load config's from last save
if ( this.configFile.exists() ) { if (this.configFile.exists()) {
this.configProps = FileUtils.loadMap(this.configFile); this.configProps = FileUtils.loadMap(this.configFile);
} else { } else {
this.configProps = new ConcurrentHashMap<String, String>(); this.configProps = new ConcurrentHashMap<String, String>();
@ -108,12 +109,12 @@ public class serverSwitch
// remove all values from config that do not appear in init // remove all values from config that do not appear in init
this.configRemoved = new ConcurrentHashMap<String, String>(); this.configRemoved = new ConcurrentHashMap<String, String>();
synchronized ( this.configProps ) { synchronized (this.configProps) {
Iterator<String> i = this.configProps.keySet().iterator(); Iterator<String> i = this.configProps.keySet().iterator();
String key; String key;
while ( i.hasNext() ) { while (i.hasNext()) {
key = i.next(); key = i.next();
if ( !(initProps.containsKey(key)) ) { if (!(initProps.containsKey(key))) {
this.configRemoved.put(key, this.configProps.get(key)); this.configRemoved.put(key, this.configProps.get(key));
i.remove(); i.remove();
} }
@ -124,7 +125,8 @@ public class serverSwitch
initProps.putAll(this.configProps); initProps.putAll(this.configProps);
this.configProps = initProps; this.configProps = initProps;
// save result; this may initially create a config file after initialization // save result; this may initially create a config file after
// initialization
saveConfig(); saveConfig();
} }
@ -132,7 +134,7 @@ public class serverSwitch
this.workerThreads = new TreeMap<String, BusyThread>(); this.workerThreads = new TreeMap<String, BusyThread>();
// init busy state control // init busy state control
//this.serverJobs = 0; // this.serverJobs = 0;
// init server tracking // init server tracking
serverAccessTracker.init( serverAccessTracker.init(
@ -142,48 +144,95 @@ public class serverSwitch
} }
/** /**
* get my public IP, either set statically or figure out dynamic * get my public IP, either set statically or figure out dynamic This method
* This method is deprecated because there may be more than one public IPs of this peer, * is deprecated because there may be more than one public IPs of this peer,
* i.e. one IPv4 and one IPv6. Please use myPublicIPs() instead * i.e. one IPv4 and one IPv6. Please use myPublicIPs() instead
*
* @return the public IP of this peer, if known * @return the public IP of this peer, if known
*/ */
@Deprecated @Deprecated
public String myPublicIP() { public String myPublicIP() {
// if a static IP was configured, we have to return it here ... // if a static IP was configured, we have to return it here ...
final String staticIP = getConfig("staticIP", ""); final String staticIP = getConfig("staticIP", "");
if ( staticIP.length() > 0 ) return staticIP; if (staticIP.length() > 0)
return staticIP;
// otherwise we return the real IP address of this host // otherwise we return the real IP address of this host
final InetAddress pLIP = Domains.myPublicLocalIP(); final InetAddress pLIP = Domains.myPublicLocalIP();
if ( pLIP != null ) return pLIP.getHostAddress(); if (pLIP != null)
return pLIP.getHostAddress();
return null; return null;
} }
/** /**
* Get all my public IPs. If there was a static IP assignment, only one, that IP is returned. * Get all my public IPs. If there was a static IP assignment, only one,
* that IP is returned.
*
* @return a set of IPs which are supposed to be my own public IPs * @return a set of IPs which are supposed to be my own public IPs
*/ */
public Set<String> myPublicIPs() { public Set<String> myPublicIPs() {
// if a static IP was configured, we have to return it here ... // if a static IP was configured, we have to return it here ...
final String staticIP = getConfig("staticIP", ""); final String staticIP = getConfig("staticIP", "");
if ( staticIP.length() > 0 ) { if (staticIP.length() > 0) {
HashSet<String> h = new HashSet<>(); HashSet<String> h = new HashSet<>();
h.add(staticIP); h.add(staticIP);
return h; return h;
} }
Set<String> h = new LinkedHashSet<>(); Set<String> h = new LinkedHashSet<>();
for (InetAddress i: Domains.myPublicIPv6()) { for (InetAddress i : Domains.myPublicIPv6()) {
String s = i.getHostAddress(); String s = i.getHostAddress();
if (Seed.isProperIP(s)) h.add(s); if (Seed.isProperIP(s))
h.add(s);
} }
for (InetAddress i: Domains.myPublicIPv4()) { for (InetAddress i : Domains.myPublicIPv4()) {
String s = i.getHostAddress(); String s = i.getHostAddress();
if (Seed.isProperIP(s)) h.add(s); if (Seed.isProperIP(s))
h.add(s);
} }
return h; return h;
} }
/**
* Gets public port. May differ from local port due to NATting. This method
* will eventually removed once nobody used IPv4 anymore, but until then we
* have to live with it.
*
* @param key
* original key from config (for example "port" or "port.ssl")
* @param dflt
* default value which will be used if no value is found
* @return the public port of this system on its IPv4 address
*
* @see #getLocalPort(String, int)
*/
public int getPublicPort(final String key, final int dflt) {
if (isConnectedViaUpnp && upnpPortMap.containsKey(key)) {
return upnpPortMap.get(key).intValue();
}
// TODO: add way of setting and retrieving port for manual NAT
return getConfigInt(key, dflt);
}
/**
* Wrapper for {@link #getConfigInt(String, int)} to have a more consistent
* API.
*
* @param key
* original key from config (for example "port" or "port.ssl")
* @param dflt
* default value which will be used if no value is found
* @return the local port of this system
* @see #getPublicPort(String, int)
*/
public int getLocalPort(final String key, final int dflt) {
return getConfigInt(key, dflt);
}
// a logger for this switchboard // a logger for this switchboard
public void setLog(final ConcurrentLog log) { public void setLog(final ConcurrentLog log) {
this.log = log; this.log = log;
@ -195,12 +244,14 @@ public class serverSwitch
/** /**
* add whole map of key-value pairs to config * add whole map of key-value pairs to config
*
* @param otherConfigs * @param otherConfigs
*/ */
public void setConfig(final Map<String, String> otherConfigs) { public void setConfig(final Map<String, String> otherConfigs) {
final Iterator<Map.Entry<String, String>> i = otherConfigs.entrySet().iterator(); final Iterator<Map.Entry<String, String>> i = otherConfigs.entrySet()
.iterator();
Map.Entry<String, String> entry; Map.Entry<String, String> entry;
while ( i.hasNext() ) { while (i.hasNext()) {
entry = i.next(); entry = i.next();
setConfig(entry.getKey(), entry.getValue()); setConfig(entry.getKey(), entry.getValue());
} }
@ -225,7 +276,7 @@ public class serverSwitch
public void setConfig(final String key, final String value) { public void setConfig(final String key, final String value) {
// set the value // set the value
final String oldValue = this.configProps.put(key, value); final String oldValue = this.configProps.put(key, value);
if ( oldValue == null || !value.equals(oldValue) ) { if (oldValue == null || !value.equals(oldValue)) {
saveConfig(); saveConfig();
} }
} }
@ -237,8 +288,11 @@ public class serverSwitch
/** /**
* Gets a configuration parameter from the properties. * Gets a configuration parameter from the properties.
* *
* @param key name of the configuration parameter * @param key
* @param dflt default value which will be used in case parameter can not be found or if it is invalid * name of the configuration parameter
* @param dflt
* default value which will be used in case parameter can not be
* found or if it is invalid
* @return value if the parameter or default value * @return value if the parameter or default value
*/ */
public String getConfig(final String key, final String dflt) { public String getConfig(final String key, final String dflt) {
@ -246,7 +300,7 @@ public class serverSwitch
final String s = this.configProps.get(key); final String s = this.configProps.get(key);
// return value // return value
if ( s == null ) { if (s == null) {
return dflt; return dflt;
} }
return s; return s;
@ -255,14 +309,17 @@ public class serverSwitch
/** /**
* Gets a configuration parameter from the properties. * Gets a configuration parameter from the properties.
* *
* @param key name of the configuration parameter * @param key
* @param dflt default value which will be used in case parameter can not be found or if it is invalid * name of the configuration parameter
* @param dflt
* default value which will be used in case parameter can not be
* found or if it is invalid
* @return value if the parameter or default value * @return value if the parameter or default value
*/ */
public long getConfigLong(final String key, final long dflt) { public long getConfigLong(final String key, final long dflt) {
try { try {
return Long.parseLong(getConfig(key, Long.toString(dflt))); return Long.parseLong(getConfig(key, Long.toString(dflt)));
} catch (final NumberFormatException e ) { } catch (final NumberFormatException e) {
return dflt; return dflt;
} }
} }
@ -270,29 +327,60 @@ public class serverSwitch
/** /**
* Gets a configuration parameter from the properties. * Gets a configuration parameter from the properties.
* *
* @param key name of the configuration parameter * @param key
* @param dflt default value which will be used in case parameter can not be found or if it is invalid * name of the configuration parameter
* @param dflt
* default value which will be used in case parameter can not be
* found or if it is invalid
* @return value if the parameter or default value * @return value if the parameter or default value
*/ */
public float getConfigFloat(final String key, final float dflt) { public float getConfigFloat(final String key, final float dflt) {
try { try {
return Float.parseFloat(getConfig(key, Float.toString(dflt))); return Float.parseFloat(getConfig(key, Float.toString(dflt)));
} catch (final NumberFormatException e ) { } catch (final NumberFormatException e) {
return dflt; return dflt;
} }
} }
public boolean isConnectedViaUpnp() {
return isConnectedViaUpnp;
}
public void setConnectedViaUpnp(final boolean isConnectedViaUpnp) {
this.isConnectedViaUpnp = isConnectedViaUpnp;
if (!isConnectedViaUpnp) {
upnpPortMap.clear();
}
}
public void setUpnpPorts(final String key, final int port) {
upnpPortMap.put(key, Integer.valueOf(port));
}
public void removeUpnpPort(final String key) {
upnpPortMap.remove(key);
}
/** /**
* Gets a configuration parameter from the properties. * Gets a configuration parameter from the properties.
* *
* @param key name of the configuration parameter * @param key
* @param dflt default value which will be used in case parameter can not be found or if it is invalid * name of the configuration parameter
* @param dflt
* default value which will be used in case parameter can not be
* found or if it is invalid
* @return value if the parameter or default value * @return value if the parameter or default value
*/ */
public int getConfigInt(final String key, final int dflt) { public int getConfigInt(final String key, final int dflt) {
try { try {
return Integer.parseInt(getConfig(key, Integer.toString(dflt))); return Integer.parseInt(getConfig(key, Integer.toString(dflt)));
} catch (final NumberFormatException e ) {
} catch (final NumberFormatException e) {
return dflt; return dflt;
} }
} }
@ -300,8 +388,11 @@ public class serverSwitch
/** /**
* Gets a configuration parameter from the properties. * Gets a configuration parameter from the properties.
* *
* @param key name of the configuration parameter * @param key
* @param dflt default value which will be used in case parameter can not be found or if it is invalid * name of the configuration parameter
* @param dflt
* default value which will be used in case parameter can not be
* found or if it is invalid
* @return value if the parameter or default value * @return value if the parameter or default value
*/ */
public boolean getConfigBool(final String key, final boolean dflt) { public boolean getConfigBool(final String key, final boolean dflt) {
@ -311,12 +402,15 @@ public class serverSwitch
/** /**
* Create a File instance for a configuration setting specifying a path. * Create a File instance for a configuration setting specifying a path.
* *
* @param key config key * @param key
* @param dflt default path value, that is used when there is no value <code>key</code> in the * config key
* configuration. * @param dflt
* @return if the value of the setting is an absolute path String, then the returned File is derived from * default path value, that is used when there is no value
* this setting only. Otherwise the path's file is constructed from the applications root path + * <code>key</code> in the configuration.
* the relative path setting. * @return if the value of the setting is an absolute path String, then the
* returned File is derived from this setting only. Otherwise the
* path's file is constructed from the applications root path + the
* relative path setting.
*/ */
public File getDataPath(final String key, final String dflt) { public File getDataPath(final String key, final String dflt) {
return getFileByPath(key, dflt, this.dataPath); return getFileByPath(key, dflt, this.dataPath);
@ -324,6 +418,7 @@ public class serverSwitch
/** /**
* return file at path from config entry "key", or fallback to default dflt * return file at path from config entry "key", or fallback to default dflt
*
* @param key * @param key
* @param dflt * @param dflt
* @return * @return
@ -335,7 +430,8 @@ public class serverSwitch
private File getFileByPath(String key, String dflt, File prefix) { private File getFileByPath(String key, String dflt, File prefix) {
final String path = getConfig(key, dflt).replace('\\', '/'); final String path = getConfig(key, dflt).replace('\\', '/');
final File f = new File(path); final File f = new File(path);
return (f.isAbsolute() ? new File(f.getAbsolutePath()) : new File(prefix, path)); return (f.isAbsolute() ? new File(f.getAbsolutePath()) : new File(
prefix, path));
} }
public Iterator<String> configKeys() { public Iterator<String> configKeys() {
@ -352,7 +448,8 @@ public class serverSwitch
} }
/** /**
* Gets configuration parameters which have been removed during initialization. * Gets configuration parameters which have been removed during
* initialization.
* *
* @return contains parameter name as key and parameter value as value * @return contains parameter name as key and parameter value as value
*/ */
@ -360,13 +457,10 @@ public class serverSwitch
return this.configRemoved; return this.configRemoved;
} }
public void deployThread( public void deployThread(final String threadName,
final String threadName,
final String threadShortDescription, final String threadShortDescription,
final String threadLongDescription, final String threadLongDescription, final String threadMonitorURL,
final String threadMonitorURL, final BusyThread newThread, final long startupDelay) {
final BusyThread newThread,
final long startupDelay) {
deployThread( deployThread(
threadName, threadName,
threadShortDescription, threadShortDescription,
@ -380,18 +474,14 @@ public class serverSwitch
Double.parseDouble(getConfig(threadName + "_loadprereq", "9.0"))); Double.parseDouble(getConfig(threadName + "_loadprereq", "9.0")));
} }
public void deployThread( public void deployThread(final String threadName,
final String threadName,
final String threadShortDescription, final String threadShortDescription,
final String threadLongDescription, final String threadLongDescription, final String threadMonitorURL,
final String threadMonitorURL, final BusyThread newThread, final long startupDelay,
final BusyThread newThread, final long initialIdleSleep, final long initialBusySleep,
final long startupDelay,
final long initialIdleSleep,
final long initialBusySleep,
final long initialMemoryPreRequisite, final long initialMemoryPreRequisite,
final double initialLoadPreRequisite) { final double initialLoadPreRequisite) {
if ( newThread.isAlive() ) { if (newThread.isAlive()) {
throw new RuntimeException( throw new RuntimeException(
"undeployed threads must not live; they are started as part of the deployment"); "undeployed threads must not live; they are started as part of the deployment");
} }
@ -400,35 +490,38 @@ public class serverSwitch
try { try {
x = Long.parseLong(getConfig(threadName + "_idlesleep", "novalue")); x = Long.parseLong(getConfig(threadName + "_idlesleep", "novalue"));
newThread.setIdleSleep(x); newThread.setIdleSleep(x);
} catch (final NumberFormatException e ) { } catch (final NumberFormatException e) {
newThread.setIdleSleep(initialIdleSleep); newThread.setIdleSleep(initialIdleSleep);
setConfig(threadName + "_idlesleep", initialIdleSleep); setConfig(threadName + "_idlesleep", initialIdleSleep);
} }
try { try {
x = Long.parseLong(getConfig(threadName + "_busysleep", "novalue")); x = Long.parseLong(getConfig(threadName + "_busysleep", "novalue"));
newThread.setBusySleep(x); newThread.setBusySleep(x);
} catch (final NumberFormatException e ) { } catch (final NumberFormatException e) {
newThread.setBusySleep(initialBusySleep); newThread.setBusySleep(initialBusySleep);
setConfig(threadName + "_busysleep", initialBusySleep); setConfig(threadName + "_busysleep", initialBusySleep);
} }
try { try {
x = Long.parseLong(getConfig(threadName + "_memprereq", "novalue")); x = Long.parseLong(getConfig(threadName + "_memprereq", "novalue"));
newThread.setMemPreReqisite(x); newThread.setMemPreReqisite(x);
} catch (final NumberFormatException e ) { } catch (final NumberFormatException e) {
newThread.setMemPreReqisite(initialMemoryPreRequisite); newThread.setMemPreReqisite(initialMemoryPreRequisite);
setConfig(threadName + "_memprereq", initialMemoryPreRequisite); setConfig(threadName + "_memprereq", initialMemoryPreRequisite);
} }
try { try {
final double load = Double.parseDouble(getConfig(threadName + "_loadprereq", "novalue")); final double load = Double.parseDouble(getConfig(threadName
+ "_loadprereq", "novalue"));
newThread.setLoadPreReqisite(load); newThread.setLoadPreReqisite(load);
} catch (final NumberFormatException e ) { } catch (final NumberFormatException e) {
newThread.setLoadPreReqisite(initialLoadPreRequisite); newThread.setLoadPreReqisite(initialLoadPreRequisite);
setConfig(threadName + "_loadprereq", (float)initialLoadPreRequisite); setConfig(threadName + "_loadprereq",
(float) initialLoadPreRequisite);
} }
newThread.setDescription(threadShortDescription, threadLongDescription, threadMonitorURL); newThread.setDescription(threadShortDescription, threadLongDescription,
threadMonitorURL);
this.workerThreads.put(threadName, newThread); this.workerThreads.put(threadName, newThread);
// start the thread // start the thread
if ( this.workerThreads.containsKey(threadName) ) { if (this.workerThreads.containsKey(threadName)) {
newThread.start(); newThread.start();
} }
} }
@ -437,52 +530,55 @@ public class serverSwitch
return this.workerThreads.get(threadName); return this.workerThreads.get(threadName);
} }
public void setThreadPerformance( public void setThreadPerformance(final String threadName,
final String threadName, final long idleMillis, final long busyMillis,
final long idleMillis, final long memprereqBytes, final double loadprereq) {
final long busyMillis,
final long memprereqBytes,
final double loadprereq) {
final BusyThread thread = this.workerThreads.get(threadName); final BusyThread thread = this.workerThreads.get(threadName);
if ( thread != null ) { if (thread != null) {
setConfig(threadName + "_idlesleep", thread.setIdleSleep(idleMillis)); setConfig(threadName + "_idlesleep",
setConfig(threadName + "_busysleep", thread.setBusySleep(busyMillis)); thread.setIdleSleep(idleMillis));
setConfig(threadName + "_busysleep",
thread.setBusySleep(busyMillis));
setConfig(threadName + "_memprereq", memprereqBytes); setConfig(threadName + "_memprereq", memprereqBytes);
thread.setMemPreReqisite(memprereqBytes); thread.setMemPreReqisite(memprereqBytes);
setConfig(threadName + "_loadprereq", (float)loadprereq); setConfig(threadName + "_loadprereq", (float) loadprereq);
thread.setLoadPreReqisite(loadprereq); thread.setLoadPreReqisite(loadprereq);
} }
} }
public synchronized void terminateThread(final String threadName, final boolean waitFor) { public synchronized void terminateThread(final String threadName,
if ( this.workerThreads.containsKey(threadName) ) { final boolean waitFor) {
((WorkflowThread) this.workerThreads.get(threadName)).terminate(waitFor); if (this.workerThreads.containsKey(threadName)) {
((WorkflowThread) this.workerThreads.get(threadName))
.terminate(waitFor);
this.workerThreads.remove(threadName); this.workerThreads.remove(threadName);
} }
} }
public void intermissionAllThreads(final long pause) { public void intermissionAllThreads(final long pause) {
final Iterator<String> e = this.workerThreads.keySet().iterator(); final Iterator<String> e = this.workerThreads.keySet().iterator();
while ( e.hasNext() ) { while (e.hasNext()) {
this.workerThreads.get(e.next()).intermission(pause); this.workerThreads.get(e.next()).intermission(pause);
} }
} }
public synchronized void terminateAllThreads(final boolean waitFor) { public synchronized void terminateAllThreads(final boolean waitFor) {
Iterator<String> e = this.workerThreads.keySet().iterator(); Iterator<String> e = this.workerThreads.keySet().iterator();
while ( e.hasNext() ) { while (e.hasNext()) {
((WorkflowThread) this.workerThreads.get(e.next())).terminate(false); ((WorkflowThread) this.workerThreads.get(e.next()))
.terminate(false);
} }
if ( waitFor ) { if (waitFor) {
e = this.workerThreads.keySet().iterator(); e = this.workerThreads.keySet().iterator();
while ( e.hasNext() ) { while (e.hasNext()) {
((WorkflowThread) this.workerThreads.get(e.next())).terminate(true); ((WorkflowThread) this.workerThreads.get(e.next()))
.terminate(true);
e.remove(); e.remove();
} }
} }
} }
public Iterator<String> /*of serverThread-Names (String)*/threadNames() { public Iterator<String> /* of serverThread-Names (String) */threadNames() {
return this.workerThreads.keySet().iterator(); return this.workerThreads.keySet().iterator();
} }
@ -504,47 +600,64 @@ public class serverSwitch
} }
/** /**
* Retrieve text data (e. g. config file) from file file may be an url or a filename with path relative to * Retrieve text data (e. g. config file) from file file may be an url or a
* rootPath parameter * filename with path relative to rootPath parameter
* *
* @param file url or filename * @param file
* @param rootPath searchpath for file * url or filename
* @param file file to use when remote fetching fails (null if unused) * @param rootPath
* searchpath for file
* @param file
* file to use when remote fetching fails (null if unused)
*/ */
public Reader getConfigFileFromWebOrLocally(final String uri, final String rootPath, final File file) public Reader getConfigFileFromWebOrLocally(final String uri,
throws IOException, final String rootPath, final File file) throws IOException,
FileNotFoundException { FileNotFoundException {
if ( uri.startsWith("http://") || uri.startsWith("https://") ) { if (uri.startsWith("http://") || uri.startsWith("https://")) {
final String[] uris = uri.split(","); final String[] uris = uri.split(",");
for ( String netdef : uris ) { for (String netdef : uris) {
netdef = netdef.trim(); netdef = netdef.trim();
try { try {
final RequestHeader reqHeader = new RequestHeader(); final RequestHeader reqHeader = new RequestHeader();
reqHeader.put(HeaderFramework.USER_AGENT, ClientIdentification.yacyInternetCrawlerAgent.userAgent); reqHeader
final HTTPClient client = new HTTPClient(ClientIdentification.yacyInternetCrawlerAgent); .put(HeaderFramework.USER_AGENT,
ClientIdentification.yacyInternetCrawlerAgent.userAgent);
final HTTPClient client = new HTTPClient(
ClientIdentification.yacyInternetCrawlerAgent);
client.setHeader(reqHeader.entrySet()); client.setHeader(reqHeader.entrySet());
byte[] data = client.GETbytes(uri, getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin"), getConfig(SwitchboardConstants.ADMIN_ACCOUNT_B64MD5, ""), false); byte[] data = client
if ( data == null || data.length == 0 ) { .GETbytes(
uri,
getConfig(
SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME,
"admin"),
getConfig(
SwitchboardConstants.ADMIN_ACCOUNT_B64MD5,
""), false);
if (data == null || data.length == 0) {
continue; continue;
} }
// save locally in case next fetch fails // save locally in case next fetch fails
if ( file != null ) { if (file != null) {
FileOutputStream f = new FileOutputStream(file); FileOutputStream f = new FileOutputStream(file);
f.write(data); f.write(data);
f.close(); f.close();
} }
return new InputStreamReader(new BufferedInputStream(new ByteArrayInputStream(data))); return new InputStreamReader(new BufferedInputStream(
} catch (final Exception e ) { new ByteArrayInputStream(data)));
} catch (final Exception e) {
continue; continue;
} }
} }
if ( file != null && file.exists() ) { if (file != null && file.exists()) {
return new FileReader(file); return new FileReader(file);
} }
throw new FileNotFoundException(); throw new FileNotFoundException();
} }
final File f = (uri.length() > 0 && uri.startsWith("/")) ? new File(uri) : new File(rootPath, uri); final File f = (uri.length() > 0 && uri.startsWith("/")) ? new File(uri)
if (f.exists()) return new FileReader(f); : new File(rootPath, uri);
if (f.exists())
return new FileReader(f);
throw new FileNotFoundException(f.toString()); throw new FileNotFoundException(f.toString());
} }
@ -562,7 +675,8 @@ public class serverSwitch
/** /**
* Generates a random password of a given length. * Generates a random password of a given length.
* *
* @param length length o password * @param length
* length o password
* @return password of given length * @return password of given length
*/ */
public String genRandomPassword(final int length) { public String genRandomPassword(final int length) {
@ -570,13 +684,16 @@ public class serverSwitch
pwGenerator.nextBytes(bytes); pwGenerator.nextBytes(bytes);
return Digest.encodeMD5Hex(bytes); return Digest.encodeMD5Hex(bytes);
} }
/** /**
* set/remember jetty server * set/remember jetty server
*
* @param jettyserver * @param jettyserver
*/ */
public void setHttpServer(YaCyHttpServer jettyserver) { public void setHttpServer(YaCyHttpServer jettyserver) {
this.httpserver = jettyserver; this.httpserver = jettyserver;
} }
public YaCyHttpServer getHttpServer() { public YaCyHttpServer getHttpServer() {
return httpserver; return httpserver;
} }

@ -35,6 +35,7 @@ import net.yacy.search.Switchboard;
import org.bitlet.weupnp.GatewayDevice; import org.bitlet.weupnp.GatewayDevice;
import org.bitlet.weupnp.GatewayDiscover; import org.bitlet.weupnp.GatewayDiscover;
import org.bitlet.weupnp.PortMappingEntry;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
public class UPnP { public class UPnP {
@ -42,7 +43,7 @@ public class UPnP {
private static final ConcurrentLog LOG = new ConcurrentLog("UPNP"); private static final ConcurrentLog LOG = new ConcurrentLog("UPNP");
private static final Switchboard SB = Switchboard.getSwitchboard(); private static final Switchboard SB = Switchboard.getSwitchboard();
private static Map<InetAddress, GatewayDevice> GATEWAY_DEVICES = null; private static GatewayDevice gatewayDevice;
private static final Map<UPnPMappingType, UPnPMapping> MAPPINGS = new EnumMap<>( private static final Map<UPnPMappingType, UPnPMapping> MAPPINGS = new EnumMap<>(
UPnPMappingType.class); UPnPMappingType.class);
@ -53,20 +54,23 @@ public class UPnP {
"server.https", "TCP", "YaCy HTTPS")); "server.https", "TCP", "YaCy HTTPS"));
} }
private static final int MIN_CANDIDATE_PORT = 49152;
private static final int MAX_CANDIDATE_PORT = 65535;
private static boolean init() { private static boolean init() {
boolean init = true; boolean init = true;
try { try {
if (GATEWAY_DEVICES == null) { if (gatewayDevice == null || !gatewayDevice.isConnected()) {
GATEWAY_DEVICES = new GatewayDiscover().discover(); final GatewayDiscover discover = new GatewayDiscover();
discover.discover();
gatewayDevice = discover.getValidGateway();
} }
} catch (IOException | SAXException | ParserConfigurationException e) { } catch (IOException | SAXException | ParserConfigurationException e) {
init = false; init = false;
} }
if (GATEWAY_DEVICES != null) { if (gatewayDevice != null) {
for (final GatewayDevice gatewayDevice : GATEWAY_DEVICES.values()) {
LOG.info("found device: " + gatewayDevice.getFriendlyName()); LOG.info("found device: " + gatewayDevice.getFriendlyName());
}
} else { } else {
LOG.info("no device found"); LOG.info("no device found");
init = false; init = false;
@ -91,6 +95,8 @@ public class UPnP {
addPortMapping(entry.getKey(), mapping, addPortMapping(entry.getKey(), mapping,
SB.getConfigInt(mapping.getConfigPortKey(), 0)); SB.getConfigInt(mapping.getConfigPortKey(), 0));
} }
SB.setConnectedViaUpnp(true);
} }
/** /**
@ -102,6 +108,8 @@ public class UPnP {
return; return;
} }
SB.setConnectedViaUpnp(false);
UPnPMapping mapping; UPnPMapping mapping;
for (final Entry<UPnPMappingType, UPnPMapping> entry : MAPPINGS for (final Entry<UPnPMappingType, UPnPMapping> entry : MAPPINGS
.entrySet()) { .entrySet()) {
@ -123,7 +131,7 @@ public class UPnP {
* @param port * @param port
* port number to map * port number to map
*/ */
public static void addPortMapping(final UPnPMappingType type, private static void addPortMapping(final UPnPMappingType type,
final UPnPMapping mapping, final int port) { final UPnPMapping mapping, final int port) {
if (port < 1) { if (port < 1) {
@ -137,26 +145,44 @@ public class UPnP {
if ((mapping.isConfigEnabledKeyEmpty() || SB.getConfigBool( if ((mapping.isConfigEnabledKeyEmpty() || SB.getConfigBool(
mapping.getConfigEnabledKey(), false)) mapping.getConfigEnabledKey(), false))
&& mapping.getPort() == 0 && mapping.getPort() == 0
&& ((GATEWAY_DEVICES != null) || init())) { && ((gatewayDevice != null) || init())) {
String localHostIP; String localHostIP;
boolean mapped; boolean mapped;
String msg; String msg;
for (final GatewayDevice gatewayDevice : GATEWAY_DEVICES.values()) {
try { try {
localHostIP = toString(gatewayDevice.getLocalAddress()); localHostIP = toString(gatewayDevice.getLocalAddress());
mapped = gatewayDevice.addPortMapping(port, port, int portCandidate = port;
while (isInUse(portCandidate) && portCandidate > 0) {
LOG.info(portCandidate + " in use, trying different port.");
portCandidate = getNewPortCandidate(portCandidate);
}
if (portCandidate > 0) {
mapped = gatewayDevice.addPortMapping(portCandidate, port,
localHostIP, mapping.getProtocol(), localHostIP, mapping.getProtocol(),
mapping.getDescription()); mapping.getDescription());
msg = "port " + port + " on device " msg = "mapped port " + port + " to port " + portCandidate
+ gatewayDevice.getFriendlyName(); + " on device " + gatewayDevice.getFriendlyName()
+ ", external IP is "
+ gatewayDevice.getExternalIPAddress();
} else {
mapped = false;
msg = "no free port found";
}
if (mapped) { if (mapped) {
LOG.info("mapped " + msg); LOG.info("mapped " + msg);
mapping.setPort(port); mapping.setPort(portCandidate);
SB.setUpnpPorts(mapping.getConfigPortKey(), portCandidate);
} else { } else {
LOG.warn("could not map " + msg); LOG.warn("could not map " + msg);
} }
@ -165,7 +191,6 @@ public class UPnP {
} }
} }
} }
}
/** /**
* Delete current port mapping. * Delete current port mapping.
@ -173,16 +198,15 @@ public class UPnP {
* @param mapping * @param mapping
* to delete * to delete
*/ */
public static void deletePortMapping(final UPnPMapping mapping) { private static void deletePortMapping(final UPnPMapping mapping) {
if (mapping.getPort() > 0 && GATEWAY_DEVICES != null) { if (mapping.getPort() > 0 && gatewayDevice != null) {
boolean unmapped; boolean unmapped;
String msg; String msg;
for (final GatewayDevice gatewayDevice : GATEWAY_DEVICES.values()) {
try { try {
unmapped = gatewayDevice.deletePortMapping( unmapped = gatewayDevice.deletePortMapping(mapping.getPort(),
mapping.getPort(), mapping.getProtocol()); mapping.getProtocol());
msg = "port " + mapping.getPort() + " on device " msg = "port " + mapping.getPort() + " on device "
+ gatewayDevice.getFriendlyName(); + gatewayDevice.getFriendlyName();
@ -200,7 +224,6 @@ public class UPnP {
mapping.setPort(0); // reset mapped port mapping.setPort(0); // reset mapped port
} }
}
/** /**
* Gets currently mapped port. * Gets currently mapped port.
@ -219,6 +242,30 @@ public class UPnP {
return MAPPINGS.get(type).getPort(); return MAPPINGS.get(type).getPort();
} }
public static int getNewPortCandidate(final int oldCandidate) {
int newPortCandidate = Math.min(
Math.max(MIN_CANDIDATE_PORT, oldCandidate + 1),
MAX_CANDIDATE_PORT);
if (newPortCandidate == MAX_CANDIDATE_PORT) {
newPortCandidate = -1;
}
return newPortCandidate;
}
private static boolean isInUse(final int port) {
try {
return gatewayDevice != null
&& gatewayDevice.getSpecificPortMappingEntry(port, "TCP",
new PortMappingEntry());
} catch (IOException | SAXException e) {
return false;
}
}
private static String toString(final InetAddress inetAddress) { private static String toString(final InetAddress inetAddress) {
final String localHostIP; final String localHostIP;

@ -202,7 +202,7 @@ public final class yacy {
sb.setConfig("memoryTotalAfterStartup", startupMemTotal); sb.setConfig("memoryTotalAfterStartup", startupMemTotal);
// start gui if wanted // start gui if wanted
if (gui) YaCyApp.start("localhost", (int) sb.getConfigLong("port", 8090)); if (gui) YaCyApp.start("localhost", sb.getLocalPort("port", 8090));
// hardcoded, forced, temporary value-migration // hardcoded, forced, temporary value-migration
sb.setConfig("htTemplatePath", "htroot/env/templates"); sb.setConfig("htTemplatePath", "htroot/env/templates");
@ -277,7 +277,7 @@ public final class yacy {
HTTPClient.setDefaultUserAgent(ClientIdentification.yacyInternetCrawlerAgent.userAgent); HTTPClient.setDefaultUserAgent(ClientIdentification.yacyInternetCrawlerAgent.userAgent);
// start main threads // start main threads
final int port = sb.getConfigInt("port", 8090); final int port = sb.getLocalPort("port", 8090);
try { try {
// start http server // start http server
YaCyHttpServer httpServer; YaCyHttpServer httpServer;

Loading…
Cancel
Save