Skip to content

Commit

Permalink
Improved UPnP. (still not perfect)
Browse files Browse the repository at this point in the history
*) set HTTPS port if enabled
*) improved data structures (may not be final)
*) moved UPnP to own package
  • Loading branch information
marcnause committed Aug 26, 2014
1 parent ec5b1d9 commit 2af56fa
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 38 deletions.
11 changes: 6 additions & 5 deletions htroot/ConfigBasic.java
Expand Up @@ -46,7 +46,8 @@
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 {

Expand Down Expand Up @@ -118,11 +119,11 @@ public static serverObjects respond(final RequestHeader header, final serverObje
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;
Expand All @@ -141,7 +142,7 @@ public static serverObjects respond(final RequestHeader header, final serverObje

// renew upnp port mapping
if (upnp) {
UPnP.addPortMapping();
UPnP.addPortMappings();
}

String host = null;
Expand Down Expand Up @@ -265,7 +266,7 @@ public static serverObjects respond(final RequestHeader header, final serverObje
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");
Expand Down
8 changes: 4 additions & 4 deletions source/net/yacy/search/Switchboard.java
Expand Up @@ -199,8 +199,8 @@
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;
Expand Down Expand Up @@ -315,7 +315,7 @@ public Switchboard(final File dataPath, final File appPath, final String initPat

// 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
Expand Down Expand Up @@ -1771,7 +1771,7 @@ public synchronized void close() {
Domains.close();
AccessTracker.dumpLog();
Switchboard.urlBlacklist.close();
UPnP.deletePortMapping();
UPnP.deletePortMappings();
this.tray.remove();
try {
HTTPClient.closeConnectionManager();
Expand Down Expand Up @@ -2274,7 +2274,7 @@ && getConfig(SwitchboardConstants.ADMIN_ACCOUNT_B64MD5, "").isEmpty() ) {

// 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
Expand Down
Expand Up @@ -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
Expand All @@ -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;

Expand All @@ -46,10 +44,14 @@ public class UPnP {

private static Map<InetAddress, GatewayDevice> 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<UPnPMappingType, UPnPMapping> 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;
Expand All @@ -74,33 +76,68 @@ private static boolean init() {
}

/**
* 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<UPnPMappingType, UPnPMapping> 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<UPnPMappingType, UPnPMapping> entry : MAPPINGS
.entrySet()) {
mapping = entry.getValue();
deletePortMapping(mapping);
}
}

/**
* Add TCP port mapping to all gateway devices on the network.<br/>
* Add port mapping to all gateway devices on the network.<br/>
* 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;
Expand All @@ -111,14 +148,15 @@ public static void addPortMapping(final int port) { // TODO: don't map
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);
}
Expand All @@ -131,19 +169,22 @@ public static void addPortMapping(final int port) { // TODO: don't map

/**
* 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) {
Expand All @@ -157,17 +198,25 @@ public static void deletePortMapping() {
}
}

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) {
Expand Down
89 changes: 89 additions & 0 deletions 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 <code>null</code> 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();
}

}

0 comments on commit 2af56fa

Please sign in to comment.