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);
ssl = post.getBoolean("withssl");
} 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);
}
if (ssl) prop.put("withsslenabled_sslport",env.getHttpServer().getSslPort());
@ -266,7 +266,7 @@ public class ConfigBasic {
// set default values
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);
lang = env.getConfig("locale.language", "default"); // re-assign lang, may have changed
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();
if (myaddress == null) {
myaddress = "localhost:" + sb.getConfig("port", "8090");
myaddress = "localhost:" + sb.getLocalPort("port", 8090);
}
prop.put("myaddress", myaddress);
return prop;

@ -35,7 +35,7 @@ public class ConfigSearchBox {
final Switchboard sb = (Switchboard) env;
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);
return prop;
}

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

@ -39,7 +39,7 @@ public class Load_MediawikiWiki {
// define visible variables
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 String repository = "http://" + a + "/repository/";
prop.put("starturl", (intranet) ? repository : "http://");

@ -39,7 +39,7 @@ public class Load_PHPBB3 {
// define visible variables
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 String repository = "http://" + a + "/repository/";
prop.put("starturl", (intranet) ? repository : "http://");

@ -99,7 +99,7 @@ public class SettingsAck_p {
/*
* display port info
*/
prop.putHTML("info_port", env.getConfig("port", "8090"));
prop.put("info_port", env.getLocalPort("port", 8090));
prop.put("info_restart", "0");
// read and process data
@ -483,7 +483,7 @@ public class SettingsAck_p {
// change https port
if (post.containsKey("port.ssl")) {
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);
}
prop.put("info_port.ssl", port);

@ -73,7 +73,7 @@ public final class Settings_p {
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("staticIP", env.getConfig("staticIP", ""));

@ -206,7 +206,7 @@ public class Table_API_p {
}
// 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
prop.put("showexec", l.isEmpty() ? 0 : 1);
@ -297,7 +297,7 @@ public class Table_API_p {
} else {
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_filter", typefilter.pattern());
prop.put("showtable_list_" + count + "_scheduler_query", query.pattern());

@ -122,7 +122,7 @@ public class push_p {
sb.indexingDocumentProcessor.enQueue(in);
}
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++;
} catch (MalformedURLException e) {
e.printStackTrace();

@ -40,7 +40,7 @@ public class opensearchdescription {
if (env.getConfigBool(SwitchboardConstants.GREETING_NETWORK_NAME, false)) promoteSearchPageGreeting = env.getConfig("network.unit.description", "");
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";
final serverObjects prop = new serverObjects();

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

@ -91,7 +91,7 @@ public class yacysearch_location {
if (query.length() > 0 && (metatag || search_title || search_publisher || search_creator || search_subject)) try {
// 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>();
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, "");
if (env.getConfigBool(SwitchboardConstants.GREETING_NETWORK_NAME, false)) promoteSearchPageGreeting = env.getConfig("network.unit.description", "");
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 boolean global = post.get("kml_resource", "local").equals("global");

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

@ -82,7 +82,7 @@ public class Jetty9HttpServerImpl implements YaCyHttpServer {
final SSLContext sslContext = initSslContext(sb);
if (sslContext != null) {
int sslport = sb.getConfigInt("port.ssl", 8443);
int sslport = sb.getLocalPort("port.ssl", 8443);
sslContextFactory.setSslContext(sslContext);
// 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
final Connector[] cons = server.getConnectors();
final int port = Switchboard.getSwitchboard().getConfigInt("port", 8090);
final int sslport = Switchboard.getSwitchboard().getConfigInt("port.ssl", 8443);
final int port = Switchboard.getSwitchboard().getLocalPort("port", 8090);
final int sslport = Switchboard.getSwitchboard().getLocalPort("port.ssl", 8443);
for (Connector con : cons) {
// check http connector
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);
// 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.PORT, Long.toString(port));
newSeed.dna.put(Seed.PORT, Integer.toString(port));
return newSeed;
}

@ -958,7 +958,7 @@ public final class SeedDB implements AlternativeDomainNames {
if (this.mySeed == null) initMySeed();
if ((seed == this.mySeed) && (!(seed.isOnline()))) {
// 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));
} else {

@ -294,7 +294,7 @@ public final class Switchboard extends serverSwitch {
super(dataPath, appPath, initPath, configPath);
sb = this;
// 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)) {
throw new RuntimeException(
"a server is already running on the YaCy port "
@ -2453,7 +2453,7 @@ public final class Switchboard extends serverSwitch {
startupAction = false;
// 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() ) {
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 indexSizeTime = 0;
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
final long uptime = (System.currentTimeMillis() - this.startupTime) / 1000;

@ -162,13 +162,13 @@ public final class HTTPDemon {
final InetAddress hostAddress = Domains.dnsResolve(clientIP);
if (hostAddress == null) {
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()) {
tp.put("host", Domains.myPublicLocalIP().getHostAddress());
tp.put("port", switchboard.getConfig("port", "8090"));
tp.put("port", switchboard.getLocalPort("port", 8090));
} else {
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());

File diff suppressed because it is too large Load Diff

@ -35,6 +35,7 @@ import net.yacy.search.Switchboard;
import org.bitlet.weupnp.GatewayDevice;
import org.bitlet.weupnp.GatewayDiscover;
import org.bitlet.weupnp.PortMappingEntry;
import org.xml.sax.SAXException;
public class UPnP {
@ -42,7 +43,7 @@ public class UPnP {
private static final ConcurrentLog LOG = new ConcurrentLog("UPNP");
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<>(
UPnPMappingType.class);
@ -53,20 +54,23 @@ public class UPnP {
"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() {
boolean init = true;
try {
if (GATEWAY_DEVICES == null) {
GATEWAY_DEVICES = new GatewayDiscover().discover();
if (gatewayDevice == null || !gatewayDevice.isConnected()) {
final GatewayDiscover discover = new GatewayDiscover();
discover.discover();
gatewayDevice = discover.getValidGateway();
}
} catch (IOException | SAXException | ParserConfigurationException e) {
init = false;
}
if (GATEWAY_DEVICES != null) {
for (final GatewayDevice gatewayDevice : GATEWAY_DEVICES.values()) {
LOG.info("found device: " + gatewayDevice.getFriendlyName());
}
if (gatewayDevice != null) {
LOG.info("found device: " + gatewayDevice.getFriendlyName());
} else {
LOG.info("no device found");
init = false;
@ -91,6 +95,8 @@ public class UPnP {
addPortMapping(entry.getKey(), mapping,
SB.getConfigInt(mapping.getConfigPortKey(), 0));
}
SB.setConnectedViaUpnp(true);
}
/**
@ -102,6 +108,8 @@ public class UPnP {
return;
}
SB.setConnectedViaUpnp(false);
UPnPMapping mapping;
for (final Entry<UPnPMappingType, UPnPMapping> entry : MAPPINGS
.entrySet()) {
@ -123,7 +131,7 @@ public class UPnP {
* @param port
* port number to map
*/
public static void addPortMapping(final UPnPMappingType type,
private static void addPortMapping(final UPnPMappingType type,
final UPnPMapping mapping, final int port) {
if (port < 1) {
@ -137,32 +145,49 @@ public class UPnP {
if ((mapping.isConfigEnabledKeyEmpty() || SB.getConfigBool(
mapping.getConfigEnabledKey(), false))
&& mapping.getPort() == 0
&& ((GATEWAY_DEVICES != null) || init())) {
&& ((gatewayDevice != null) || init())) {
String localHostIP;
boolean mapped;
String msg;
for (final GatewayDevice gatewayDevice : GATEWAY_DEVICES.values()) {
try {
localHostIP = toString(gatewayDevice.getLocalAddress());
try {
localHostIP = toString(gatewayDevice.getLocalAddress());
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(port, port,
mapped = gatewayDevice.addPortMapping(portCandidate, port,
localHostIP, mapping.getProtocol(),
mapping.getDescription());
msg = "port " + port + " on device "
+ gatewayDevice.getFriendlyName();
if (mapped) {
LOG.info("mapped " + msg);
mapping.setPort(port);
} else {
LOG.warn("could not map " + msg);
}
} catch (IOException | SAXException e) {
LOG.severe("mapping error: " + e.getMessage());
msg = "mapped port " + port + " to port " + portCandidate
+ " on device " + gatewayDevice.getFriendlyName()
+ ", external IP is "
+ gatewayDevice.getExternalIPAddress();
} else {
mapped = false;
msg = "no free port found";
}
if (mapped) {
LOG.info("mapped " + msg);
mapping.setPort(portCandidate);
SB.setUpnpPorts(mapping.getConfigPortKey(), portCandidate);
} else {
LOG.warn("could not map " + msg);
}
} catch (IOException | SAXException e) {
LOG.severe("mapping error: " + e.getMessage());
}
}
}
@ -173,33 +198,31 @@ public class UPnP {
* @param mapping
* to delete
*/
public static void deletePortMapping(final UPnPMapping mapping) {
if (mapping.getPort() > 0 && GATEWAY_DEVICES != null) {
private static void deletePortMapping(final UPnPMapping mapping) {
if (mapping.getPort() > 0 && gatewayDevice != null) {
boolean unmapped;
String msg;
for (final GatewayDevice gatewayDevice : GATEWAY_DEVICES.values()) {
try {
unmapped = gatewayDevice.deletePortMapping(
mapping.getPort(), mapping.getProtocol());
msg = "port " + mapping.getPort() + " on device "
+ gatewayDevice.getFriendlyName();
try {
unmapped = gatewayDevice.deletePortMapping(mapping.getPort(),
mapping.getProtocol());
if (unmapped) {
LOG.info("unmapped " + msg);
} else {
LOG.warn("could not unmap " + msg);
}
msg = "port " + mapping.getPort() + " on device "
+ gatewayDevice.getFriendlyName();
} catch (SAXException | IOException e) {
LOG.severe("unmapping error: " + e.getMessage());
if (unmapped) {
LOG.info("unmapped " + msg);
} else {
LOG.warn("could not unmap " + msg);
}
}
mapping.setPort(0); // reset mapped port
} catch (SAXException | IOException e) {
LOG.severe("unmapping error: " + e.getMessage());
}
}
mapping.setPort(0); // reset mapped port
}
/**
@ -219,6 +242,30 @@ public class UPnP {
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) {
final String localHostIP;

@ -202,7 +202,7 @@ public final class yacy {
sb.setConfig("memoryTotalAfterStartup", startupMemTotal);
// 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
sb.setConfig("htTemplatePath", "htroot/env/templates");
@ -277,7 +277,7 @@ public final class yacy {
HTTPClient.setDefaultUserAgent(ClientIdentification.yacyInternetCrawlerAgent.userAgent);
// start main threads
final int port = sb.getConfigInt("port", 8090);
final int port = sb.getLocalPort("port", 8090);
try {
// start http server
YaCyHttpServer httpServer;

Loading…
Cancel
Save