jellyfin/Mono.Nat/Pmp/Pmp.cs
2016-09-11 03:33:53 -04:00

118 lines
4.9 KiB
C#

//
// 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.
}
}
}
}