141 lines
4.0 KiB
C#
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
|
|
}
|
|
}
|
|
}
|
|
} |