1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
namespace MonoTests.Helpers {
public static class NetworkHelpers
{
static Random rndPort = new Random ();
static HashSet<int> portsTable = new HashSet<int> ();
public static int FindFreePort ()
{
return LocalEphemeralEndPoint ().Port;
}
public static IPEndPoint LocalEphemeralEndPoint ()
{
int counter = 0;
while (counter < 1000) {
var testingPort = rndPort.Next (10000, 60000);
var ep = new IPEndPoint (IPAddress.Loopback, testingPort);
lock (portsTable) {
if (portsTable.Contains (testingPort))
continue;
++counter;
try {
using (var socket = new Socket (ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) {
socket.Bind (ep);
socket.Close ();
}
portsTable.Add (testingPort);
return ep;
} catch (SocketException) { }
}
}
throw new ApplicationException ($"Could not find available local port after {counter} retries");
}
// Bind to the specified address using a system-assigned port.
// Returns the assigned port.
public static void Bind (this Socket socket, IPAddress address, out int port)
{
socket.Bind (new IPEndPoint (address, 0));
port = ((IPEndPoint) socket.LocalEndPoint).Port;
}
// Bind to the specified address using a system-assigned port.
// Returns the resulting end local end point.
public static void Bind (this Socket socket, IPAddress address, out IPEndPoint ep)
{
socket.Bind (new IPEndPoint (address, 0));
ep = (IPEndPoint) socket.LocalEndPoint;
}
// Creates and starts a TcpListener using a system-assigned port.
// Returns the assigned port.
public static TcpListener CreateAndStartTcpListener (out int port)
{
var rv = new TcpListener (0);
rv.Start ();
port = ((IPEndPoint) rv.LocalEndpoint).Port;
return rv;
}
// Creates and starts a TcpListener using a system-assigned port.
// Returns the resulting local end point.
public static TcpListener CreateAndStartTcpListener (out IPEndPoint ep)
{
var rv = new TcpListener (0);
rv.Start ();
ep = (IPEndPoint) rv.LocalEndpoint;
return rv;
}
// Creates and starts a TcpListener using the specified address and a system-assigned port.
// Returns the assigned port.
public static TcpListener CreateAndStartTcpListener (IPAddress address, out int port)
{
var rv = new TcpListener (address, 0);
rv.Start ();
port = ((IPEndPoint) rv.LocalEndpoint).Port;
return rv;
}
// Creates and starts a TcpListener using the specified address and a system-assigned port.
// Returns the resulting local end point.
public static TcpListener CreateAndStartTcpListener (IPAddress address, out IPEndPoint ep)
{
var rv = new TcpListener (address, 0);
rv.Start ();
ep = (IPEndPoint) rv.LocalEndpoint;
return rv;
}
// Creates and starts an HttpListener using the specified host, port,
// path and authSchemes.
//
// If specified, the initializer will be called immediately after the
// HttpListener is created (typical usage would be to set/change
// properties before starting the listener)
public static HttpListener CreateAndStartHttpListener (string host, int port, string path, AuthenticationSchemes? authSchemes = null, Action<HttpListener> initializer = null)
{
var prefix = host + port + path;
HttpListener listener = new HttpListener ();
if (initializer != null)
initializer (listener);
if (authSchemes.HasValue)
listener.AuthenticationSchemes = authSchemes.Value;
listener.Prefixes.Add (prefix);
listener.Start ();
return listener;
}
// Creates and starts an HttpListener using the specified host, path
// and authSchemes. The method will try to find an unused port, and
// use that (multiple attempts with random port numbers will be made).
//
// If specified, the initializer will be called immediately after the
// HttpListener is created (typical usage would be to set/change
// properties before starting the listener). Be aware that the
// initializer can be called multiple times (in case multiple creation
// attempts have to be made).
public static HttpListener CreateAndStartHttpListener (string host, out int port, string path, AuthenticationSchemes? authSchemes = null, Action<HttpListener> initializer = null)
{
// There's no way to create an HttpListener with a system-assigned port.
// So we use NetworkHelpers.FindFreePort, and re-try if we fail because someone else has already used the port.
for (int i = 0; i < 10; i++) {
try {
var tentativePort = NetworkHelpers.FindFreePort ();
var listener = CreateAndStartHttpListener (host, tentativePort, path, authSchemes, initializer);
port = tentativePort;
return listener;
} catch (SocketException se) {
if (se.SocketErrorCode == SocketError.AddressAlreadyInUse)
continue;
throw;
}
}
throw new Exception ("Unable to create HttpListener after 10 attempts");
}
// Creates and starts an HttpListener using the specified host, path
// and authSchemes. The method will try to find an unused port, and
// use that (multiple attempts with random port numbers will be made).
//
// If specified, the initializer will be called immediately after the
// HttpListener is created (typical usage would be to set/change
// properties before starting the listener). Be aware that the
// initializer can be called multiple times (in case multiple creation
// attempts have to be made).
//
// The resulting uri will also be returned (this is just host + port + path).
public static HttpListener CreateAndStartHttpListener (string host, out int port, string path, out string uri, AuthenticationSchemes? authSchemes = null, Action<HttpListener> initializer = null)
{
var rv = CreateAndStartHttpListener (host, out port, path, authSchemes, initializer);
uri = host + port + path;
return rv;
}
}
}
|