Get Available Socket Port
// /* **********************************************************************************
// *
// * Copyright (c) Sky Sanders. All rights reserved.
// *
// * This source code is subject to terms and conditions of the Microsoft Public
// * License (Ms-PL). A copy of the license can be found in the license.htm file
// * included in this distribution.
// *
// * You must not remove this notice, or any other, from this software.
// *
// * **********************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
namespace Salient.Net
{
public static class IPUtility
{
/// <summary>
/// Returns first available port on the specified IP address. The port scan excludes ports that are open on ANY loopback adapter.
/// If the address upon which a port is requested is an 'ANY' address all ports that are open on ANY IP are excluded.
/// </summary>
/// <param name="rangeStart"></param>
/// <param name="rangeEnd"></param>
/// <param name="ip">The IP address upon which to search for available port.</param>
/// <param name="includeIdlePorts">If true includes ports in TIME_WAIT state in results. TIME_WAIT state is typically cool down period for recently released ports.</param>
/// <returns></returns>
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
public static ushort GetAvailablePort(UInt16 rangeStart, UInt16 rangeEnd, IPAddress ip, bool includeIdlePorts)
{
IPGlobalProperties ipProps = IPGlobalProperties.GetIPGlobalProperties();
// if the ip we want a port on is an 'any' or loopback port we need to exclude all ports that are active on any IP
Func<IPAddress, bool> isIpAnyOrLoopBack = i => IPAddress.Any.Equals(i) ||
IPAddress.IPv6Any.Equals(i) ||
IPAddress.Loopback.Equals(i) ||
IPAddress.IPv6Loopback.
Equals(i);
// get all active ports on specified IP.
List<ushort> excludedPorts = new List<ushort>();
// if a port is open on an 'any' or 'loopback' interface then include it in the excludedPorts
excludedPorts.AddRange(from n in ipProps.GetActiveTcpConnections()
where
n.LocalEndPoint.Port >= rangeStart
&& n.LocalEndPoint.Port <= rangeEnd
&&
(isIpAnyOrLoopBack(ip) || n.LocalEndPoint.Address.Equals(ip) ||
isIpAnyOrLoopBack(n.LocalEndPoint.Address))
&& (!includeIdlePorts || n.State != TcpState.TimeWait)
select (ushort) n.LocalEndPoint.Port);
excludedPorts.AddRange(from n in ipProps.GetActiveTcpListeners()
where n.Port >= rangeStart && n.Port <= rangeEnd
&&
(isIpAnyOrLoopBack(ip) || n.Address.Equals(ip) || isIpAnyOrLoopBack(n.Address))
select (ushort) n.Port);
excludedPorts.AddRange(from n in ipProps.GetActiveUdpListeners()
where n.Port >= rangeStart && n.Port <= rangeEnd
&&
(isIpAnyOrLoopBack(ip) || n.Address.Equals(ip) || isIpAnyOrLoopBack(n.Address))
select (ushort) n.Port);
excludedPorts.Sort();
for (ushort port = rangeStart; port <= rangeEnd; port++)
{
if (!excludedPorts.Contains(port))
{
return port;
}
}
return 0;
}
public static NetworkInterface[] GetActiveNetworkInterfaces()
{
return
(NetworkInterface.GetAllNetworkInterfaces().Where(p => p.OperationalStatus == OperationalStatus.Up)).
ToArray();
}
}
}
Related examples in the same category