|
@@ -0,0 +1,174 @@
|
|
|
+using MediaBrowser.Controller;
|
|
|
+using MediaBrowser.Controller.Configuration;
|
|
|
+using MediaBrowser.Controller.Plugins;
|
|
|
+using MediaBrowser.Model.Logging;
|
|
|
+using Mono.Nat;
|
|
|
+using System;
|
|
|
+using System.IO;
|
|
|
+using System.Text;
|
|
|
+
|
|
|
+namespace MediaBrowser.Server.Implementations.EntryPoints
|
|
|
+{
|
|
|
+ public class ExternalPortForwarding : IServerEntryPoint
|
|
|
+ {
|
|
|
+ private readonly IServerApplicationHost _appHost;
|
|
|
+ private readonly ILogger _logger;
|
|
|
+ private readonly IServerConfigurationManager _config;
|
|
|
+
|
|
|
+ private bool _isStarted;
|
|
|
+
|
|
|
+ public ExternalPortForwarding(ILogger logger, IServerApplicationHost appHost, IServerConfigurationManager config)
|
|
|
+ {
|
|
|
+ _logger = logger;
|
|
|
+ _appHost = appHost;
|
|
|
+ _config = config;
|
|
|
+
|
|
|
+ _config.ConfigurationUpdated += _config_ConfigurationUpdated;
|
|
|
+ }
|
|
|
+
|
|
|
+ void _config_ConfigurationUpdated(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ var enable = _config.Configuration.EnableUPnP;
|
|
|
+
|
|
|
+ if (enable && !_isStarted)
|
|
|
+ {
|
|
|
+ Reload();
|
|
|
+ }
|
|
|
+ else if (!enable && _isStarted)
|
|
|
+ {
|
|
|
+ DisposeNat();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Run()
|
|
|
+ {
|
|
|
+ NatUtility.Logger = new LogWriter(_logger);
|
|
|
+
|
|
|
+ Reload();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Reload()
|
|
|
+ {
|
|
|
+ if (_config.Configuration.EnableUPnP)
|
|
|
+ {
|
|
|
+ _logger.Debug("Starting NAT discovery");
|
|
|
+
|
|
|
+ NatUtility.DeviceFound += NatUtility_DeviceFound;
|
|
|
+ NatUtility.DeviceLost += NatUtility_DeviceLost;
|
|
|
+ NatUtility.UnhandledException += NatUtility_UnhandledException;
|
|
|
+ NatUtility.StartDiscovery();
|
|
|
+
|
|
|
+ _isStarted = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
|
|
+ {
|
|
|
+ var ex = e.ExceptionObject as Exception;
|
|
|
+
|
|
|
+ if (ex == null)
|
|
|
+ {
|
|
|
+ _logger.Error("Unidentified error reported by Mono.Nat");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Seeing some blank exceptions coming through here
|
|
|
+ _logger.ErrorException("Error reported by Mono.Nat: ", ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void NatUtility_DeviceFound(object sender, DeviceEventArgs e)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var device = e.Device;
|
|
|
+ _logger.Debug("NAT device found: {0}", device.LocalAddress.ToString());
|
|
|
+
|
|
|
+ CreateRules(device);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ _logger.ErrorException("Error creating port forwarding rules", ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void CreateRules(INatDevice device)
|
|
|
+ {
|
|
|
+ var info = _appHost.GetSystemInfo();
|
|
|
+
|
|
|
+ CreatePortMap(device, info.HttpServerPortNumber);
|
|
|
+
|
|
|
+ if (info.WebSocketPortNumber != info.HttpServerPortNumber)
|
|
|
+ {
|
|
|
+ CreatePortMap(device, info.WebSocketPortNumber);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void CreatePortMap(INatDevice device, int port)
|
|
|
+ {
|
|
|
+ _logger.Info("Creating port map on port {0}", port);
|
|
|
+
|
|
|
+ device.CreatePortMap(new Mapping(Protocol.Tcp, port, port)
|
|
|
+ {
|
|
|
+ Description = "Media Browser Server"
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ void NatUtility_DeviceLost(object sender, DeviceEventArgs e)
|
|
|
+ {
|
|
|
+ var device = e.Device;
|
|
|
+ _logger.Debug("NAT device lost: {0}", device.LocalAddress.ToString());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ DisposeNat();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void DisposeNat()
|
|
|
+ {
|
|
|
+ _logger.Debug("Stopping NAT discovery");
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ NatUtility.DeviceFound -= NatUtility_DeviceFound;
|
|
|
+ NatUtility.DeviceLost -= NatUtility_DeviceLost;
|
|
|
+ NatUtility.UnhandledException -= NatUtility_UnhandledException;
|
|
|
+ NatUtility.StopDiscovery();
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ _logger.ErrorException("Error stopping NAT Discovery", ex);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ _isStarted = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private class LogWriter : TextWriter
|
|
|
+ {
|
|
|
+ private readonly ILogger _logger;
|
|
|
+
|
|
|
+ public LogWriter(ILogger logger)
|
|
|
+ {
|
|
|
+ _logger = logger;
|
|
|
+ }
|
|
|
+
|
|
|
+ public override Encoding Encoding
|
|
|
+ {
|
|
|
+ get { return Encoding.UTF8; }
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void WriteLine(string format, params object[] arg)
|
|
|
+ {
|
|
|
+ _logger.Debug(format, arg);
|
|
|
+ }
|
|
|
+
|
|
|
+ public override void WriteLine(string value)
|
|
|
+ {
|
|
|
+ _logger.Debug(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|