Files

141 lines
4.0 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using EmbedIO.Net.Internal;
using Swan.Logging;
namespace EmbedIO.Net
{
/// <summary>
/// Represents the EndPoint Manager.
/// </summary>
public static class EndPointManager
{
private static readonly ConcurrentDictionary<IPAddress, ConcurrentDictionary<int, EndPointListener>> IPToEndpoints = new ();
/// <summary>
/// Gets or sets a value indicating whether [use IPv6]. By default, this flag is set.
/// </summary>
/// <value>
/// <c>true</c> if [use IPv6]; otherwise, <c>false</c>.
/// </value>
public static bool UseIpv6 { get; set; } = true;
internal static void AddListener(HttpListener listener)
{
var added = new List<string>();
try
{
foreach (var prefix in listener.Prefixes)
{
AddPrefix(prefix, listener);
added.Add(prefix);
}
}
catch (Exception ex)
{
ex.Log(nameof(AddListener));
foreach (var prefix in added)
{
RemovePrefix(prefix, listener);
}
throw;
}
}
internal static void RemoveEndPoint(EndPointListener epl, IPEndPoint ep)
{
if (IPToEndpoints.TryGetValue(ep.Address, out var p))
{
if (p.TryRemove(ep.Port, out _) && p.Count == 0)
{
_ = IPToEndpoints.TryRemove(ep.Address, out _);
}
}
epl.Dispose();
}
internal static void RemoveListener(HttpListener listener)
{
foreach (var prefix in listener.Prefixes)
{
RemovePrefix(prefix, listener);
}
}
internal static void AddPrefix(string p, HttpListener listener)
{
var lp = new ListenerPrefix(p);
if (!lp.IsValid())
{
throw new HttpListenerException(400, "Invalid path.");
}
// listens on all the interfaces if host name cannot be parsed by IPAddress.
var epl = GetEpListener(lp.Host, lp.Port, listener, lp.Secure);
epl.AddPrefix(lp, listener);
}
private static EndPointListener GetEpListener(string host, int port, HttpListener listener, bool secure = false)
{
var address = ResolveAddress(host);
var p = IPToEndpoints.GetOrAdd(address, x => new ConcurrentDictionary<int, EndPointListener>());
return p.GetOrAdd(port, x => new EndPointListener(listener, address, x, secure));
}
private static IPAddress ResolveAddress(string host)
{
if (host == "*" || host == "+" || host == "0.0.0.0")
{
return UseIpv6 ? IPAddress.IPv6Any : IPAddress.Any;
}
if (IPAddress.TryParse(host, out var address))
{
return address;
}
try
{
var hostEntry = new IPHostEntry {
HostName = host,
AddressList = Dns.GetHostAddresses(host),
};
return hostEntry.AddressList[0];
}
catch
{
return UseIpv6 ? IPAddress.IPv6Any : IPAddress.Any;
}
}
private static void RemovePrefix(string prefix, HttpListener listener)
{
try
{
var lp = new ListenerPrefix(prefix);
if (!lp.IsValid())
{
return;
}
var epl = GetEpListener(lp.Host, lp.Port, listener, lp.Secure);
epl.RemovePrefix(lp);
}
catch (SocketException)
{
// ignored
}
}
}
}