175 lines
4.8 KiB
C#
175 lines
4.8 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|