File: NetworkHelpers.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (171 lines) | stat: -rw-r--r-- 6,011 bytes parent folder | download | duplicates (5)
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;
		}

	}
}