diff --git a/.gitattributes b/.gitattributes
index 3b5eef6f415..d20a2d5ab6b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -17819,6 +17819,7 @@ forge-gui/src/main/java/forge/util/XmlUtil.java -text
forge-gui/src/main/java/forge/util/gui/SGuiChoose.java -text
forge-gui/src/main/java/forge/util/gui/SOptionPane.java -text
forge-gui/src/main/java/forge/util/package-info.java -text
+forge-gui/src/main/resources/log4jConfig.config -text
forge-gui/src/main/resources/proxy-template.ftl -text
forge-gui/src/site/apt/index.apt -text
forge-gui/tools/PerSetTracking.py svneol=native#text/x-python
diff --git a/forge-gui/pom.xml b/forge-gui/pom.xml
index f51b829c623..e2af288c748 100644
--- a/forge-gui/pom.xml
+++ b/forge-gui/pom.xml
@@ -10,6 +10,16 @@
forge-gui
Forge Gui
+
+
+ 4thline-repo
+ http://4thline.org/m2
+
+ false
+
+
+
+
forge
@@ -51,6 +61,16 @@
netty-all
4.0.25.Final
compile
-
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+ org.fourthline.cling
+ cling-support
+ 2.0.1
+
diff --git a/forge-gui/src/main/java/forge/net/FServerManager.java b/forge-gui/src/main/java/forge/net/FServerManager.java
index c8dab788713..5200e64e3f6 100644
--- a/forge-gui/src/main/java/forge/net/FServerManager.java
+++ b/forge-gui/src/main/java/forge/net/FServerManager.java
@@ -21,6 +21,7 @@ import forge.net.game.NetEvent;
import forge.net.game.ReplyEvent;
import forge.net.game.UpdateLobbyPlayerEvent;
import forge.net.game.server.RemoteClient;
+import forge.properties.ForgeConstants;
import forge.util.ITriggerEvent;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
@@ -40,11 +41,19 @@ import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.io.Serializable;
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import org.apache.log4j.PropertyConfigurator;
+import org.fourthline.cling.UpnpService;
+import org.fourthline.cling.UpnpServiceImpl;
+import org.fourthline.cling.support.igd.PortMappingListener;
+import org.fourthline.cling.support.model.PortMapping;
+
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
@@ -55,15 +64,29 @@ public final class FServerManager {
private boolean isHosting = false;
private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
private final EventLoopGroup workerGroup = new NioEventLoopGroup();
+ private UpnpService upnpService = null;
private final Map clients = Maps.newTreeMap();
private ServerGameLobby localLobby;
private ILobbyListener lobbyListener;
+ private final Thread shutdownHook = new Thread(new Runnable() {
+ @Override public final void run() {
+ if (isHosting()) {
+ stopServer(false);
+ }
+ }
+ });
private FServerManager() {
}
+ /**
+ * Get the singleton instance of {@link FServerManager}.
+ *
+ * @return the singleton FServerManager.
+ */
public static FServerManager getInstance() {
if (instance == null) {
+ PropertyConfigurator.configure(ForgeConstants.ASSETS_DIR + "/src/main/resources/log4jConfig.config");
instance = new FServerManager();
}
return instance;
@@ -103,6 +126,8 @@ public final class FServerManager {
}
}).start();
+ mapNatPort(port);
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
isHosting = true;
} catch (final InterruptedException e) {
e.printStackTrace();
@@ -110,8 +135,18 @@ public final class FServerManager {
}
public void stopServer() {
+ stopServer(true);
+ }
+ private void stopServer(final boolean removeShutdownHook) {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
+ if (upnpService != null) {
+ upnpService.shutdown();
+ upnpService = null;
+ }
+ if (removeShutdownHook) {
+ Runtime.getRuntime().removeShutdownHook(shutdownHook);
+ }
isHosting = false;
}
@@ -167,10 +202,21 @@ public final class FServerManager {
return null;
}
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- stopServer();
+ private void mapNatPort(final int port) {
+ final String localAddress;
+ try {
+ localAddress = Inet4Address.getLocalHost().getHostAddress();
+ } catch (final UnknownHostException e) {
+ throw new RuntimeException(e);
+ }
+
+ final PortMapping portMapping = new PortMapping(port, localAddress, PortMapping.Protocol.TCP, "Forge");
+ if (upnpService != null) {
+ // Safeguard shutdown call, to prevent lingering port mappings
+ upnpService.shutdown();
+ }
+ upnpService = new UpnpServiceImpl(new PortMappingListener(portMapping));
+ upnpService.getControlPoint().search();
}
private class MessageHandler extends ChannelInboundHandlerAdapter {
diff --git a/forge-gui/src/main/resources/log4jConfig.config b/forge-gui/src/main/resources/log4jConfig.config
new file mode 100644
index 00000000000..cfd8e8470ee
--- /dev/null
+++ b/forge-gui/src/main/resources/log4jConfig.config
@@ -0,0 +1,9 @@
+# Set root logger level to DEBUG and its only appender to A1.
+log4j.rootLogger=ALL, A1
+
+# A1 is set to be a ConsoleAppender.
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n