From 2af56fa37d90a0a8ed2060574f2b14770092b6df Mon Sep 17 00:00:00 2001 From: Marc Nause Date: Tue, 26 Aug 2014 22:47:13 +0200 Subject: [PATCH] Improved UPnP. (still not perfect) *) set HTTPS port if enabled *) improved data structures (may not be final) *) moved UPnP to own package --- htroot/ConfigBasic.java | 11 +- source/net/yacy/search/Switchboard.java | 8 +- source/net/yacy/utils/{ => upnp}/UPnP.java | 107 +++++++++++++----- source/net/yacy/utils/upnp/UPnPMapping.java | 89 +++++++++++++++ .../net/yacy/utils/upnp/UPnPMappingType.java | 37 ++++++ 5 files changed, 214 insertions(+), 38 deletions(-) rename source/net/yacy/utils/{ => upnp}/UPnP.java (58%) create mode 100644 source/net/yacy/utils/upnp/UPnPMapping.java create mode 100644 source/net/yacy/utils/upnp/UPnPMappingType.java diff --git a/htroot/ConfigBasic.java b/htroot/ConfigBasic.java index 7612a1816..3af305669 100644 --- a/htroot/ConfigBasic.java +++ b/htroot/ConfigBasic.java @@ -46,7 +46,8 @@ import net.yacy.search.SwitchboardConstants; import net.yacy.server.serverObjects; import net.yacy.server.serverSwitch; import net.yacy.server.http.HTTPDFileHandler; -import net.yacy.utils.UPnP; +import net.yacy.utils.upnp.UPnPMappingType; +import net.yacy.utils.upnp.UPnP; public class ConfigBasic { @@ -118,11 +119,11 @@ public class ConfigBasic { if (post != null && post.containsKey("port")) { // hack to allow checkbox upnp = post.containsKey("enableUpnp"); if (upnp && !sb.getConfigBool(SwitchboardConstants.UPNP_ENABLED, false)) { - UPnP.addPortMapping(); + UPnP.addPortMappings(); } sb.setConfig(SwitchboardConstants.UPNP_ENABLED, upnp); if (!upnp) { - UPnP.deletePortMapping(); + UPnP.deletePortMappings(); } } else { upnp = false; @@ -141,7 +142,7 @@ public class ConfigBasic { // renew upnp port mapping if (upnp) { - UPnP.addPortMapping(); + UPnP.addPortMappings(); } String host = null; @@ -265,7 +266,7 @@ public class ConfigBasic { prop.put("upnp", "1"); prop.put("upnp_enabled", upnp_enabled ? "1" : "0"); if (upnp_enabled) { - prop.put("upnp_success", (UPnP.getMappedPort() > 0) ? "2" : "1"); + prop.put("upnp_success", (UPnP.getMappedPort(UPnPMappingType.HTTP) > 0) ? "2" : "1"); } else { prop.put("upnp_success", "0"); diff --git a/source/net/yacy/search/Switchboard.java b/source/net/yacy/search/Switchboard.java index cff705d11..75fbfbb9a 100644 --- a/source/net/yacy/search/Switchboard.java +++ b/source/net/yacy/search/Switchboard.java @@ -199,8 +199,8 @@ import net.yacy.search.schema.WebgraphConfiguration; import net.yacy.server.serverSwitch; import net.yacy.server.http.RobotsTxtConfig; import net.yacy.utils.CryptoLib; -import net.yacy.utils.UPnP; import net.yacy.utils.crypt; +import net.yacy.utils.upnp.UPnP; import net.yacy.visualization.CircleTool; import com.google.common.io.Files; @@ -315,7 +315,7 @@ public final class Switchboard extends serverSwitch { // UPnP port mapping if ( getConfigBool(SwitchboardConstants.UPNP_ENABLED, false) ) { - InstantBusyThread.oneTimeJob(UPnP.class, "addPortMapping", 0); + InstantBusyThread.oneTimeJob(UPnP.class, "addPortMappings", 0); } // init TrayIcon if possible @@ -1771,7 +1771,7 @@ public final class Switchboard extends serverSwitch { Domains.close(); AccessTracker.dumpLog(); Switchboard.urlBlacklist.close(); - UPnP.deletePortMapping(); + UPnP.deletePortMappings(); this.tray.remove(); try { HTTPClient.closeConnectionManager(); @@ -2274,7 +2274,7 @@ public final class Switchboard extends serverSwitch { // check if we are reachable and try to map port again if not (e.g. when router rebooted) if ( getConfigBool(SwitchboardConstants.UPNP_ENABLED, false) && this.peers.mySeed().isJunior() ) { - UPnP.addPortMapping(); + UPnP.addPortMappings(); } // after all clean up is done, check the resource usage diff --git a/source/net/yacy/utils/UPnP.java b/source/net/yacy/utils/upnp/UPnP.java similarity index 58% rename from source/net/yacy/utils/UPnP.java rename to source/net/yacy/utils/upnp/UPnP.java index e6c860248..dcd9574f8 100644 --- a/source/net/yacy/utils/UPnP.java +++ b/source/net/yacy/utils/upnp/UPnP.java @@ -4,10 +4,6 @@ // // This is a part of YaCy, a peer-to-peer based web search engine // -// $LastChangedDate$ -// $LastChangedRevision$ -// $LastChangedBy$ -// // LICENSE // // This program is free software; you can redistribute it and/or modify @@ -24,11 +20,13 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -package net.yacy.utils; +package net.yacy.utils.upnp; import java.io.IOException; import java.net.InetAddress; +import java.util.EnumMap; import java.util.Map; +import java.util.Map.Entry; import javax.xml.parsers.ParserConfigurationException; @@ -46,10 +44,14 @@ public class UPnP { private static Map GATEWAY_DEVICES = null; - // mapping variables - private static final String MAPPED_NAME = "YaCy"; - private static final String MAPPED_PROTOCOL = "TCP"; - private static int mappedPort; + private static final Map MAPPINGS = new EnumMap<>( + UPnPMappingType.class); + static { + MAPPINGS.put(UPnPMappingType.HTTP, new UPnPMapping("port", null, "TCP", + "YaCy HTTP")); + MAPPINGS.put(UPnPMappingType.HTTPS, new UPnPMapping("port.ssl", + "server.https", "TCP", "YaCy HTTPS")); + } private static boolean init() { boolean init = true; @@ -74,33 +76,68 @@ public class UPnP { } /** - * Add port mapping for configured port. + * Add port mappings for configured ports. + */ + public static void addPortMappings() { + if (SB == null) { + return; + } + + UPnPMapping mapping; + for (final Entry entry : MAPPINGS + .entrySet()) { + mapping = entry.getValue(); + + addPortMapping(entry.getKey(), mapping, + SB.getConfigInt(mapping.getConfigPortKey(), 0)); + } + } + + /** + * Remove all port mappings. */ - public static void addPortMapping() { + public static void deletePortMappings() { + if (SB == null) { return; } - addPortMapping(Integer.parseInt(SB.getConfig("port", "0"))); + + UPnPMapping mapping; + for (final Entry entry : MAPPINGS + .entrySet()) { + mapping = entry.getValue(); + deletePortMapping(mapping); + } } /** - * Add TCP port mapping to all gateway devices on the network.
+ * Add port mapping to all gateway devices on the network.
* Latest port mapping will be removed. * + * TODO: don't try to map already mapped port again, find alternative + * + * @param type + * mapping type + * @param mapping + * contains data about mapping * @param port + * port number to map */ - public static void addPortMapping(final int port) { // TODO: don't map - // already mapped port - // again + public static void addPortMapping(final UPnPMappingType type, + final UPnPMapping mapping, final int port) { + if (port < 1) { return; } - if (mappedPort > 0) { - deletePortMapping(); // delete old mapping first + if (mapping.getPort() > 0) { + deletePortMapping(mapping); // delete old mapping first } - if (mappedPort == 0 && ((GATEWAY_DEVICES != null) || init())) { + if ((mapping.isConfigEnabledKeyEmpty() || SB.getConfigBool( + mapping.getConfigEnabledKey(), false)) + && mapping.getPort() == 0 + && ((GATEWAY_DEVICES != null) || init())) { String localHostIP; boolean mapped; @@ -111,14 +148,15 @@ public class UPnP { localHostIP = toString(gatewayDevice.getLocalAddress()); mapped = gatewayDevice.addPortMapping(port, port, - localHostIP, MAPPED_PROTOCOL, MAPPED_NAME); + localHostIP, mapping.getProtocol(), + mapping.getDescription()); msg = "port " + port + " on device " + gatewayDevice.getFriendlyName(); if (mapped) { LOG.info("mapped " + msg); - mappedPort = port; + mapping.setPort(port); } else { LOG.warn("could not map " + msg); } @@ -131,19 +169,22 @@ public class UPnP { /** * Delete current port mapping. + * + * @param mapping + * to delete */ - public static void deletePortMapping() { - if (mappedPort > 0 && GATEWAY_DEVICES != null) { + public static void deletePortMapping(final UPnPMapping mapping) { + if (mapping.getPort() > 0 && GATEWAY_DEVICES != null) { boolean unmapped; String msg; for (final GatewayDevice gatewayDevice : GATEWAY_DEVICES.values()) { try { - unmapped = gatewayDevice.deletePortMapping(mappedPort, - MAPPED_PROTOCOL); + unmapped = gatewayDevice.deletePortMapping( + mapping.getPort(), mapping.getProtocol()); - msg = "port " + mappedPort + " on device " + msg = "port " + mapping.getPort() + " on device " + gatewayDevice.getFriendlyName(); if (unmapped) { @@ -157,17 +198,25 @@ public class UPnP { } } - mappedPort = 0; // reset mapped port + mapping.setPort(0); // reset mapped port } } /** * Gets currently mapped port. * + * @param type + * mapping type + * * @return mapped port or 0 if no port is mapped */ - public static int getMappedPort() { - return mappedPort; + public static int getMappedPort(final UPnPMappingType type) { + + if (type == null) { + return 0; + } + + return MAPPINGS.get(type).getPort(); } private static String toString(final InetAddress inetAddress) { diff --git a/source/net/yacy/utils/upnp/UPnPMapping.java b/source/net/yacy/utils/upnp/UPnPMapping.java new file mode 100644 index 000000000..e5ac7a8a6 --- /dev/null +++ b/source/net/yacy/utils/upnp/UPnPMapping.java @@ -0,0 +1,89 @@ +// UPnPMapping.java +// (C) 2014 by Marc Nause; marc.nause@gmx.de +// first published 26.08.2014 on http://yacy.net +// +// This is a part of YaCy, a peer-to-peer based web search engine +// +// LICENSE +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package net.yacy.utils.upnp; + +/** + * Simple value holder class for all values required for UPnP mapping. Class is + * package private since we only need to create new instances in the UPnP + * package. + * + * @author Marc Nause + */ +class UPnPMapping { + + private final String PROTOCOL; + private final String DESCRIPTION; + private final String CONFIG_PORT_KEY; + private final String CONFIG_ENABLED_KEY; + private int port; + + /** + * Constructor. + * + * @param configPortKey + * key for port in yacy.config + * @param configEnabledKey + * key for flag if port is enabled in yacy.config (optional, set + * to empty or null if none is required + * @param protocol + * {"TCP"|"UDP"} + * @param description + * human readable description, may be displayed in router + */ + UPnPMapping(final String configPortKey, final String configEnabledKey, + final String protocol, final String description) { + PROTOCOL = protocol; + DESCRIPTION = description; + CONFIG_PORT_KEY = configPortKey; + CONFIG_ENABLED_KEY = configEnabledKey; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getProtocol() { + return PROTOCOL; + } + + public String getDescription() { + return DESCRIPTION; + } + + public String getConfigPortKey() { + return CONFIG_PORT_KEY; + } + + public String getConfigEnabledKey() { + return CONFIG_ENABLED_KEY; + } + + public boolean isConfigEnabledKeyEmpty() { + return CONFIG_ENABLED_KEY == null || CONFIG_ENABLED_KEY.isEmpty(); + } + +} diff --git a/source/net/yacy/utils/upnp/UPnPMappingType.java b/source/net/yacy/utils/upnp/UPnPMappingType.java new file mode 100644 index 000000000..1a91a9117 --- /dev/null +++ b/source/net/yacy/utils/upnp/UPnPMappingType.java @@ -0,0 +1,37 @@ +// UPnPMapping.java +// (C) 2014 by Marc Nause; marc.nause@gmx.de +// first published 26.08.2014 on http://yacy.net +// +// This is a part of YaCy, a peer-to-peer based web search engine +// +// LICENSE +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package net.yacy.utils.upnp; + +/** + * Contains types of mappings for UPnP. At the moment we only distinguish + * between different protocols. At some point in the future we may serve the + * same protocols vie different ports for different services, but until then, + * this should be good enough. + * + * @author Marc Nause + */ +public enum UPnPMappingType { + + HTTP, HTTPS + +}