From a859902c2045867cd5ba20c6de2aae1de8ec9607 Mon Sep 17 00:00:00 2001 From: elcnesh Date: Fri, 10 Apr 2015 13:39:53 +0000 Subject: [PATCH] - Add UPnP support to Forge game server - Fix closing of server - Fix server (Netty) log configuration --- .gitattributes | 1 + forge-gui/pom.xml | 22 +++++++- .../main/java/forge/net/FServerManager.java | 54 +++++++++++++++++-- .../src/main/resources/log4jConfig.config | 9 ++++ 4 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 forge-gui/src/main/resources/log4jConfig.config 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