update port mapper

This commit is contained in:
Luke Pulverenti 2016-10-27 21:07:40 -04:00
parent 8e57296f69
commit ce043225c4
25 changed files with 773 additions and 665 deletions

View file

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Events;
using MediaBrowser.Server.Implementations.Threading;
@ -17,18 +18,20 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
{
private readonly IServerApplicationHost _appHost;
private readonly ILogger _logger;
private readonly IHttpClient _httpClient;
private readonly IServerConfigurationManager _config;
private readonly IDeviceDiscovery _deviceDiscovery;
private PeriodicTimer _timer;
private bool _isStarted;
public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config, IDeviceDiscovery deviceDiscovery)
public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient)
{
_logger = logmanager.GetLogger("PortMapper");
_appHost = appHost;
_config = config;
_deviceDiscovery = deviceDiscovery;
_httpClient = httpClient;
}
private string _lastConfigIdentifier;
@ -63,6 +66,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
public void Run()
{
NatUtility.Logger = _logger;
NatUtility.HttpClient = _httpClient;
if (_config.Configuration.EnableUPnP)
{
@ -136,7 +140,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
_usnsHandled.Add(identifier);
}
_logger.Debug("Calling Nat.Handle on " + identifier);
_logger.Debug("Found NAT device: " + identifier);
IPAddress address;
if (IPAddress.TryParse(info.Location.Host, out address))
@ -150,16 +154,23 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
{
var localAddressString = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
if (!IPAddress.TryParse(localAddressString, out localAddress))
Uri uri;
if (Uri.TryCreate(localAddressString, UriKind.Absolute, out uri))
{
return;
localAddressString = uri.Host;
if (!IPAddress.TryParse(localAddressString, out localAddress))
{
return;
}
}
}
catch
catch (Exception ex)
{
return;
}
_logger.Debug("Calling Nat.Handle on " + identifier);
NatUtility.Handle(localAddress, info, endpoint, NatProtocol.Upnp);
}
}
@ -229,13 +240,21 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
}
}
private void CreatePortMap(INatDevice device, int privatePort, int publicPort)
private async void CreatePortMap(INatDevice device, int privatePort, int publicPort)
{
_logger.Debug("Creating port map on port {0}", privatePort);
device.CreatePortMap(new Mapping(Protocol.Tcp, privatePort, publicPort)
try
{
Description = _appHost.Name
});
await device.CreatePortMap(new Mapping(Protocol.Tcp, privatePort, publicPort)
{
Description = _appHost.Name
}).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.ErrorException("Error creating port map", ex);
}
}
// As I said before, this method will be never invoked. You can remove it.

View file

@ -30,6 +30,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Threading.Tasks;
namespace Mono.Nat
{
@ -50,11 +51,7 @@ namespace Mono.Nat
set { lastSeen = value; }
}
public virtual void CreatePortMap (Mapping mapping)
{
IAsyncResult result = BeginCreatePortMap (mapping, null, null);
EndCreatePortMap(result);
}
public abstract Task CreatePortMap(Mapping mapping);
public virtual void DeletePortMap (Mapping mapping)
{

View file

@ -30,12 +30,13 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Threading.Tasks;
namespace Mono.Nat
{
public interface INatDevice
{
void CreatePortMap (Mapping mapping);
Task CreatePortMap (Mapping mapping);
void DeletePortMap (Mapping mapping);
IPAddress LocalAddress { get; }

View file

@ -54,7 +54,6 @@
<Compile Include="NatUtility.cs" />
<Compile Include="Pmp\AsyncResults\PortMapAsyncResult.cs" />
<Compile Include="Pmp\Mappers\PmpMapper.cs" />
<Compile Include="Pmp\Pmp.cs" />
<Compile Include="Pmp\PmpConstants.cs" />
<Compile Include="Pmp\PmpNatDevice.cs" />
<Compile Include="Pmp\Searchers\PmpSearcher.cs" />
@ -80,6 +79,10 @@
<Compile Include="Upnp\UpnpNatDevice.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
<Name>MediaBrowser.Common</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
<Name>MediaBrowser.Controller</Name>

View file

@ -34,9 +34,11 @@ using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Net.NetworkInformation;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Model.Logging;
using Mono.Nat.Pmp.Mappers;
using Mono.Nat.Upnp;
using Mono.Nat.Upnp.Mappers;
namespace Mono.Nat
@ -55,8 +57,9 @@ namespace Mono.Nat
public static List<NatProtocol> EnabledProtocols { get; set; }
public static ILogger Logger { get; set; }
public static IHttpClient HttpClient { get; set; }
public static bool Verbose
public static bool Verbose
{
get { return verbose; }
set { verbose = value; }
@ -153,32 +156,6 @@ namespace Mono.Nat
{
searching.Reset();
}
//This is for when you know the Gateway IP and want to skip the costly search...
public static void DirectMap(IPAddress gatewayAddress, MapperType type)
{
IMapper mapper;
switch (type)
{
case MapperType.Pmp:
mapper = new PmpMapper();
break;
case MapperType.Upnp:
mapper = new UpnpMapper(Logger);
mapper.DeviceFound += (sender, args) =>
{
if (DeviceFound != null)
DeviceFound(sender, args);
};
mapper.Map(gatewayAddress);
break;
default:
throw new InvalidOperationException("Unsuported type given");
}
searching.Reset();
}
//checks if an IP address is a private address space as defined by RFC 1918
public static bool IsPrivateAddressSpace (IPAddress address)
@ -217,11 +194,21 @@ namespace Mono.Nat
switch (protocol)
{
case NatProtocol.Upnp:
new UpnpSearcher(Logger).Handle(localAddress, deviceInfo, endpoint);
var searcher = new UpnpSearcher(Logger, HttpClient);
searcher.DeviceFound += Searcher_DeviceFound;
searcher.Handle(localAddress, deviceInfo, endpoint);
break;
default:
throw new ArgumentException("Unexpected protocol: " + protocol);
}
}
private static void Searcher_DeviceFound(object sender, DeviceEventArgs e)
{
if (DeviceFound != null)
{
DeviceFound(sender, e);
}
}
}
}

View file

@ -34,26 +34,12 @@ using Mono.Nat.Pmp;
namespace Mono.Nat.Pmp.Mappers
{
internal class PmpMapper : Pmp, IMapper
internal class PmpMapper : IMapper
{
public event EventHandler<DeviceEventArgs> DeviceFound;
static PmpMapper()
{
CreateSocketsAndAddGateways();
}
public void Map(IPAddress gatewayAddress)
{
sockets.ForEach(x => Map(x, gatewayAddress));
}
void Map(UdpClient client, IPAddress gatewayAddress)
{
// The nat-pmp search message. Must be sent to GatewayIP:53531
byte[] buffer = new byte[] { PmpConstants.Version, PmpConstants.OperationCode };
client.Send(buffer, buffer.Length, new IPEndPoint(gatewayAddress, PmpConstants.ServerPort));
}
public void Handle(IPAddress localAddres, byte[] response)

View file

@ -1,118 +0,0 @@
//
// Authors:
// Ben Motmans <ben.motmans@gmail.com>
// Nicholas Terry <nick.i.terry@gmail.com>
//
// Copyright (C) 2007 Ben Motmans
// Copyright (C) 2014 Nicholas Terry
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
namespace Mono.Nat.Pmp
{
internal abstract class Pmp
{
public static List<UdpClient> sockets;
protected static Dictionary<UdpClient, List<IPEndPoint>> gatewayLists;
internal static void CreateSocketsAndAddGateways()
{
sockets = new List<UdpClient>();
gatewayLists = new Dictionary<UdpClient, List<IPEndPoint>>();
try
{
foreach (NetworkInterface n in NetworkInterface.GetAllNetworkInterfaces())
{
if (n.OperationalStatus != OperationalStatus.Up && n.OperationalStatus != OperationalStatus.Unknown)
continue;
IPInterfaceProperties properties = n.GetIPProperties();
List<IPEndPoint> gatewayList = new List<IPEndPoint>();
foreach (GatewayIPAddressInformation gateway in properties.GatewayAddresses)
{
if (gateway.Address.AddressFamily == AddressFamily.InterNetwork)
{
gatewayList.Add(new IPEndPoint(gateway.Address, PmpConstants.ServerPort));
}
}
if (gatewayList.Count == 0)
{
/* Mono on OSX doesn't give any gateway addresses, so check DNS entries */
foreach (var gw2 in properties.DnsAddresses)
{
if (gw2.AddressFamily == AddressFamily.InterNetwork)
{
gatewayList.Add(new IPEndPoint(gw2, PmpConstants.ServerPort));
}
}
foreach (var unicast in properties.UnicastAddresses)
{
if (/*unicast.DuplicateAddressDetectionState == DuplicateAddressDetectionState.Preferred
&& unicast.AddressPreferredLifetime != UInt32.MaxValue
&& */unicast.Address.AddressFamily == AddressFamily.InterNetwork)
{
var bytes = unicast.Address.GetAddressBytes();
bytes[3] = 1;
gatewayList.Add(new IPEndPoint(new IPAddress(bytes), PmpConstants.ServerPort));
}
}
}
if (gatewayList.Count > 0)
{
foreach (UnicastIPAddressInformation address in properties.UnicastAddresses)
{
if (address.Address.AddressFamily == AddressFamily.InterNetwork)
{
UdpClient client;
try
{
client = new UdpClient(new IPEndPoint(address.Address, 0));
}
catch (SocketException)
{
continue; // Move on to the next address.
}
gatewayLists.Add(client, gatewayList);
sockets.Add(client);
}
}
}
}
}
catch (Exception)
{
// NAT-PMP does not use multicast, so there isn't really a good fallback.
}
}
}
}

View file

@ -30,6 +30,7 @@ using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Mono.Nat.Pmp
{
@ -56,6 +57,12 @@ namespace Mono.Nat.Pmp
return publicAddress;
}
public override Task CreatePortMap(Mapping mapping)
{
CreatePortMap(mapping, true);
return Task.FromResult(true);
}
public override IAsyncResult BeginCreatePortMap(Mapping mapping, AsyncCallback callback, object asyncState)
{
PortMapAsyncResult pmar = new PortMapAsyncResult (mapping.Protocol, mapping.PublicPort, PmpConstants.DefaultLeaseTime, callback, asyncState);

View file

@ -40,7 +40,7 @@ using System.Linq;
namespace Mono.Nat
{
internal class PmpSearcher : Pmp.Pmp, ISearcher
internal class PmpSearcher : ISearcher
{
static PmpSearcher instance = new PmpSearcher();
@ -60,6 +60,83 @@ namespace Mono.Nat
CreateSocketsAndAddGateways();
}
public static List<UdpClient> sockets;
protected static Dictionary<UdpClient, List<IPEndPoint>> gatewayLists;
internal static void CreateSocketsAndAddGateways()
{
sockets = new List<UdpClient>();
gatewayLists = new Dictionary<UdpClient, List<IPEndPoint>>();
try
{
foreach (NetworkInterface n in NetworkInterface.GetAllNetworkInterfaces())
{
if (n.OperationalStatus != OperationalStatus.Up && n.OperationalStatus != OperationalStatus.Unknown)
continue;
IPInterfaceProperties properties = n.GetIPProperties();
List<IPEndPoint> gatewayList = new List<IPEndPoint>();
foreach (GatewayIPAddressInformation gateway in properties.GatewayAddresses)
{
if (gateway.Address.AddressFamily == AddressFamily.InterNetwork)
{
gatewayList.Add(new IPEndPoint(gateway.Address, PmpConstants.ServerPort));
}
}
if (gatewayList.Count == 0)
{
/* Mono on OSX doesn't give any gateway addresses, so check DNS entries */
foreach (var gw2 in properties.DnsAddresses)
{
if (gw2.AddressFamily == AddressFamily.InterNetwork)
{
gatewayList.Add(new IPEndPoint(gw2, PmpConstants.ServerPort));
}
}
foreach (var unicast in properties.UnicastAddresses)
{
if (/*unicast.DuplicateAddressDetectionState == DuplicateAddressDetectionState.Preferred
&& unicast.AddressPreferredLifetime != UInt32.MaxValue
&& */unicast.Address.AddressFamily == AddressFamily.InterNetwork)
{
var bytes = unicast.Address.GetAddressBytes();
bytes[3] = 1;
gatewayList.Add(new IPEndPoint(new IPAddress(bytes), PmpConstants.ServerPort));
}
}
}
if (gatewayList.Count > 0)
{
foreach (UnicastIPAddressInformation address in properties.UnicastAddresses)
{
if (address.Address.AddressFamily == AddressFamily.InterNetwork)
{
UdpClient client;
try
{
client = new UdpClient(new IPEndPoint(address.Address, 0));
}
catch (SocketException)
{
continue; // Move on to the next address.
}
gatewayLists.Add(client, gatewayList);
sockets.Add(client);
}
}
}
}
}
catch (Exception)
{
// NAT-PMP does not use multicast, so there isn't really a good fallback.
}
}
PmpSearcher()
{
timeout = 250;

View file

@ -32,19 +32,20 @@ using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Logging;
namespace Mono.Nat.Upnp.Mappers
{
internal class UpnpMapper : Upnp, IMapper
{
public event EventHandler<DeviceEventArgs> DeviceFound;
public UdpClient Client { get; set; }
public UpnpMapper(ILogger logger)
: base(logger)
public UpnpMapper(ILogger logger, IHttpClient httpClient)
: base(logger, httpClient)
{
//Bind to local port 1900 for ssdp responses
Client = new UdpClient(1900);
@ -60,7 +61,7 @@ namespace Mono.Nat.Upnp.Mappers
new Thread(Receive).Start();
}
public void Receive()
public async void Receive()
{
while (true)
{
@ -69,28 +70,36 @@ namespace Mono.Nat.Upnp.Mappers
{
IPAddress localAddress = ((IPEndPoint)Client.Client.LocalEndPoint).Address;
byte[] data = Client.Receive(ref received);
Handle(localAddress, data, received);
await Handle(localAddress, data, received);
}
}
}
public void Handle(IPAddress localAddres, byte[] response)
{
Handle(localAddres, response, null);
}
public void Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint)
public override async Task<UpnpNatDevice> Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint)
{
// No matter what, this method should never throw an exception. If something goes wrong
// we should still be in a position to handle the next reply correctly.
try
{
UpnpNatDevice d = base.Handle(localAddress, response, endpoint);
d.GetServicesList(DeviceSetupComplete);
var d = await base.Handle(localAddress, response, endpoint).ConfigureAwait(false);
var result = await d.GetServicesList().ConfigureAwait(false);
if (result)
{
DeviceSetupComplete(d);
}
return d;
}
catch (Exception ex)
{
Logger.ErrorException("Error mapping port. Data string: {0}", ex, Encoding.UTF8.GetString(response));
return null;
}
}

View file

@ -25,6 +25,7 @@
//
using System;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
@ -54,6 +55,10 @@ namespace Mono.Nat.Upnp
}
#endregion
public override HttpRequestOptions Encode()
{
throw new NotImplementedException();
}
public override System.Net.WebRequest Encode(out byte[] body)
{

View file

@ -27,6 +27,7 @@
using System;
using System.Diagnostics;
using System.Net;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Logging;
namespace Mono.Nat.Upnp
@ -38,7 +39,7 @@ namespace Mono.Nat.Upnp
private readonly ILogger _logger;
public GetServicesMessage(string description, EndPoint hostAddress, ILogger logger)
:base(null)
: base(null)
{
if (string.IsNullOrEmpty(description))
_logger.Warn("Description is null");
@ -51,6 +52,13 @@ namespace Mono.Nat.Upnp
_logger = logger;
}
public override string Method
{
get
{
return "GET";
}
}
public override WebRequest Encode(out byte[] body)
{
@ -61,5 +69,16 @@ namespace Mono.Nat.Upnp
body = new byte[0];
return req;
}
public override HttpRequestOptions Encode()
{
var req = new HttpRequestOptions();
req.Url = "http://" + this.hostAddress.ToString() + this.servicesDescriptionUrl;
req.RequestHeaders.Add("ACCEPT-LANGUAGE", "en");
return req;
}
}
}

View file

@ -29,6 +29,7 @@ using System.IO;
using System.Globalization;
using System.Text;
using System.Xml;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
@ -51,6 +52,25 @@ namespace Mono.Nat.Upnp
}
#endregion
public override HttpRequestOptions Encode()
{
CultureInfo culture = CultureInfo.InvariantCulture;
StringBuilder builder = new StringBuilder(256);
XmlWriter writer = CreateWriter(builder);
WriteFullElement(writer, "NewRemoteHost", string.Empty);
WriteFullElement(writer, "NewExternalPort", this.mapping.PublicPort.ToString(culture));
WriteFullElement(writer, "NewProtocol", this.mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP");
WriteFullElement(writer, "NewInternalPort", this.mapping.PrivatePort.ToString(culture));
WriteFullElement(writer, "NewInternalClient", this.localIpAddress.ToString());
WriteFullElement(writer, "NewEnabled", "1");
WriteFullElement(writer, "NewPortMappingDescription", string.IsNullOrEmpty(mapping.Description) ? "Mono.Nat" : mapping.Description);
WriteFullElement(writer, "NewLeaseDuration", mapping.Lifetime.ToString());
writer.Flush();
return CreateRequest("AddPortMapping", builder.ToString());
}
public override WebRequest Encode(out byte[] body)
{

View file

@ -28,6 +28,7 @@ using System.Net;
using System.IO;
using System.Text;
using System.Xml;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
@ -41,7 +42,20 @@ namespace Mono.Nat.Upnp
this.mapping = mapping;
}
public override WebRequest Encode(out byte[] body)
public override HttpRequestOptions Encode()
{
StringBuilder builder = new StringBuilder(256);
XmlWriter writer = CreateWriter(builder);
WriteFullElement(writer, "NewRemoteHost", string.Empty);
WriteFullElement(writer, "NewExternalPort", mapping.PublicPort.ToString(MessageBase.Culture));
WriteFullElement(writer, "NewProtocol", mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP");
writer.Flush();
return CreateRequest("DeletePortMapping", builder.ToString());
}
public override WebRequest Encode(out byte[] body)
{
StringBuilder builder = new StringBuilder(256);
XmlWriter writer = CreateWriter(builder);

View file

@ -29,6 +29,7 @@ using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
@ -42,6 +43,10 @@ namespace Mono.Nat.Upnp
}
#endregion
public override HttpRequestOptions Encode()
{
return CreateRequest("GetExternalIPAddress", string.Empty);
}
public override WebRequest Encode(out byte[] body)
{

View file

@ -28,6 +28,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
@ -41,6 +42,17 @@ namespace Mono.Nat.Upnp
this.index = index;
}
public override HttpRequestOptions Encode()
{
StringBuilder sb = new StringBuilder(128);
XmlWriter writer = CreateWriter(sb);
WriteFullElement(writer, "NewPortMappingIndex", index.ToString());
writer.Flush();
return CreateRequest("GetGenericPortMappingEntry", sb.ToString());
}
public override System.Net.WebRequest Encode(out byte[] body)
{
StringBuilder sb = new StringBuilder(128);

View file

@ -29,6 +29,7 @@ using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Net;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
@ -55,6 +56,19 @@ namespace Mono.Nat.Upnp
writer.Flush();
return CreateRequest("GetSpecificPortMappingEntry", sb.ToString(), out body);
}
}
}
public override HttpRequestOptions Encode()
{
StringBuilder sb = new StringBuilder(64);
XmlWriter writer = CreateWriter(sb);
WriteFullElement(writer, "NewRemoteHost", string.Empty);
WriteFullElement(writer, "NewExternalPort", externalPort.ToString());
WriteFullElement(writer, "NewProtocol", protocol == Protocol.Tcp ? "TCP" : "UDP");
writer.Flush();
return CreateRequest("GetSpecificPortMappingEntry", sb.ToString());
}
}
}

View file

@ -27,6 +27,8 @@
using System;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
internal class CreatePortMappingResponseMessage : MessageBase
@ -38,6 +40,11 @@ namespace Mono.Nat.Upnp
}
#endregion
public override HttpRequestOptions Encode()
{
throw new NotImplementedException();
}
public override System.Net.WebRequest Encode(out byte[] body)
{
throw new NotImplementedException();

View file

@ -27,6 +27,8 @@
using System;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
internal class DeletePortMapResponseMessage : MessageBase
@ -36,6 +38,11 @@ namespace Mono.Nat.Upnp
{
}
public override HttpRequestOptions Encode()
{
throw new NotSupportedException();
}
public override System.Net.WebRequest Encode(out byte[] body)
{
throw new NotSupportedException();

View file

@ -28,6 +28,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
@ -45,6 +46,11 @@ namespace Mono.Nat.Upnp
this.externalIPAddress = IPAddress.Parse(ip);
}
public override HttpRequestOptions Encode()
{
throw new NotImplementedException();
}
public override WebRequest Encode(out byte[] body)
{
throw new NotImplementedException();

View file

@ -28,6 +28,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
@ -100,6 +101,11 @@ namespace Mono.Nat.Upnp
leaseDuration = Convert.ToInt32(data["NewLeaseDuration"].InnerText);
}
public override HttpRequestOptions Encode()
{
throw new NotImplementedException();
}
public override System.Net.WebRequest Encode(out byte[] body)
{
throw new NotImplementedException();

View file

@ -31,6 +31,7 @@ using System.Net;
using System.IO;
using System.Text;
using System.Globalization;
using MediaBrowser.Common.Net;
namespace Mono.Nat.Upnp
{
@ -71,6 +72,32 @@ namespace Mono.Nat.Upnp
return req;
}
protected HttpRequestOptions CreateRequest(string upnpMethod, string methodParameters)
{
string ss = "http://" + this.device.HostEndPoint.ToString() + this.device.ControlUrl;
NatUtility.Log("Initiating request to: {0}", ss);
var req = new HttpRequestOptions();
req.Url = ss;
req.EnableKeepAlive = false;
req.RequestContentType = "text/xml; charset=\"utf-8\"";
req.RequestHeaders.Add("SOAPACTION", "\"" + device.ServiceType + "#" + upnpMethod + "\"");
string bodyString = "<s:Envelope "
+ "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+ "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+ "<s:Body>"
+ "<u:" + upnpMethod + " "
+ "xmlns:u=\"" + device.ServiceType + "\">"
+ methodParameters
+ "</u:" + upnpMethod + ">"
+ "</s:Body>"
+ "</s:Envelope>\r\n\r\n";
req.RequestContentBytes = System.Text.Encoding.UTF8.GetBytes(bodyString);
return req;
}
public static MessageBase Decode(UpnpNatDevice device, string message)
{
XmlNode node;
@ -113,8 +140,14 @@ namespace Mono.Nat.Upnp
return null;
}
public abstract HttpRequestOptions Encode();
public abstract WebRequest Encode(out byte[] body);
public virtual string Method
{
get { return "POST"; }
}
internal static void WriteFullElement(XmlWriter writer, string element, string value)
{
writer.WriteStartElement(element);

View file

@ -36,6 +36,7 @@ using Mono.Nat.Upnp;
using System.Diagnostics;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Model.Logging;
@ -48,10 +49,12 @@ namespace Mono.Nat
private DateTime nextSearch;
private readonly ILogger _logger;
private readonly IHttpClient _httpClient;
public UpnpSearcher(ILogger logger)
public UpnpSearcher(ILogger logger, IHttpClient httpClient)
{
_logger = logger;
_httpClient = httpClient;
}
public void Search()
@ -76,7 +79,7 @@ namespace Mono.Nat
prefix. */
// We have an internet gateway device now
UpnpNatDevice d = new UpnpNatDevice(localAddress, deviceInfo, endpoint, string.Empty, _logger);
UpnpNatDevice d = new UpnpNatDevice(localAddress, deviceInfo, endpoint, string.Empty, _logger, _httpClient);
NatUtility.Log("Fetching service list: {0}", d.HostEndPoint);
OnDeviceFound(new DeviceEventArgs(d));

View file

@ -33,6 +33,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Logging;
namespace Mono.Nat.Upnp
@ -40,13 +42,15 @@ namespace Mono.Nat.Upnp
internal class Upnp
{
protected readonly ILogger Logger;
protected readonly IHttpClient HttpClient;
public Upnp(ILogger logger)
public Upnp(ILogger logger, IHttpClient httpClient)
{
Logger = logger;
HttpClient = httpClient;
}
public UpnpNatDevice Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint)
public virtual Task<UpnpNatDevice> Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint)
{
// Convert it to a string for easy parsing
string dataString = null;
@ -85,7 +89,8 @@ namespace Mono.Nat.Upnp
throw new NotSupportedException("Received non-supported device type");
// We have an internet gateway device now
return new UpnpNatDevice(localAddress, dataString, urn, Logger);
var device = new UpnpNatDevice(localAddress, dataString, urn, Logger, HttpClient);
return Task.FromResult(device);
}
}
}

File diff suppressed because it is too large Load diff