Repository navigation
Expand file tree
/
Copy pathServerConnectionInfo.cs
More file actions
179 lines (154 loc) · 6.97 KB
/
Copy pathServerConnectionInfo.cs
File metadata and controls
179 lines (154 loc) · 6.97 KB
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
172
173
174
175
176
177
178
179
using NETworkManager.Utilities;
using System;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
namespace NETworkManager.Models.Network;
/// <summary>
/// Class contains information about a server.
/// </summary>
public class ServerConnectionInfo
{
/// <summary>
/// Create an instance of <see cref="ServerConnectionInfo" />.
/// </summary>
public ServerConnectionInfo()
{
}
/// <summary>
/// Create an instance of <see cref="ServerConnectionInfo" /> with parameters. Default transport protocol is TCP.
/// </summary>
/// <param name="server">Server name or IP address.</param>
/// <param name="port">Port used for the connection.</param>
public ServerConnectionInfo(string server, int port)
{
Server = server;
Port = port;
TransportProtocol = TransportProtocol.Tcp;
}
/// <summary>
/// Create an instance of <see cref="ServerConnectionInfo" /> with parameters.
/// </summary>
/// <param name="server">Server name or IP address.</param>
/// <param name="port">Port used for the connection.</param>
/// <param name="transportProtocol">Transport protocol used for the connection.</param>
public ServerConnectionInfo(string server, int port, TransportProtocol transportProtocol)
{
Server = server;
Port = port;
TransportProtocol = transportProtocol;
}
/// <summary>
/// Server name or IP address.
/// </summary>
public string Server { get; set; }
/// <summary>
/// Port used for the connection.
/// </summary>
public int Port { get; set; }
/// <summary>
/// Transport protocol used for the connection.
/// </summary>
public TransportProtocol TransportProtocol { get; set; }
/// <summary>
/// Tries to parse a server connection string into a <see cref="ServerConnectionInfo" /> object.
/// Supports formats: IPv4, IPv4:port, IPv6, [IPv6], [IPv6]:port, hostname, hostname:port
/// </summary>
/// <param name="input">Server connection string to parse.</param>
/// <param name="serverConnectionInfo">Parsed <see cref="ServerConnectionInfo" /> object if successful.</param>
/// <param name="defaultPort">Default port to use if not specified in input.</param>
/// <param name="transportProtocol">Transport protocol to set in the parsed object.</param>
/// <returns>True if parsing was successful; otherwise, false.</returns>
public static bool TryParse(string input, out ServerConnectionInfo serverConnectionInfo, int defaultPort, TransportProtocol transportProtocol)
{
serverConnectionInfo = null;
if (string.IsNullOrWhiteSpace(input))
return false;
input = input.Trim();
Debug.WriteLine("Parse server connection info input: " + input);
// [IPv6]:Port
if (input.StartsWith('[') && input.Contains("]:"))
{
var endIndex = input.IndexOf("]:", StringComparison.Ordinal);
var ipPart = input[1..endIndex];
var portPart = input[(endIndex + 2)..];
Debug.WriteLine($"IPv6 with port detected. IP: {ipPart}, Port: {portPart}");
if (IPAddress.TryParse(ipPart, out IPAddress ip) && ip.AddressFamily == AddressFamily.InterNetworkV6 &&
int.TryParse(portPart, out int port) && port > 0 && port <= 65535)
{
serverConnectionInfo = new ServerConnectionInfo(ip.ToString(), port, transportProtocol);
return true;
}
}
// [IPv6]
else if (input.StartsWith('[') && input.EndsWith(']'))
{
var ipPart = input[1..^1];
Debug.WriteLine($"IPv6 without port detected. IP: {ipPart}");
if (IPAddress.TryParse(ipPart, out IPAddress ip) && ip.AddressFamily == AddressFamily.InterNetworkV6)
{
serverConnectionInfo = new ServerConnectionInfo(ip.ToString(), defaultPort, transportProtocol);
return true;
}
}
// IPv6 without brackets (contains multiple colons)
else if (input.Count(c => c == ':') > 1)
{
Debug.WriteLine($"IPv6 without port detected. IP: {input}");
if (IPAddress.TryParse(input, out IPAddress ip) && ip.AddressFamily == AddressFamily.InterNetworkV6)
{
serverConnectionInfo = new ServerConnectionInfo(ip.ToString(), defaultPort, transportProtocol);
return true;
}
}
// IPv4/hostname:port (single colon)
else if (input.Contains(':'))
{
var parts = input.Split([':'], 2);
Debug.WriteLine($"IPv4 or Hostname with port detected. Host: {parts[0]}, Port: {parts[1]}");
if ((RegexHelper.IPv4AddressRegex().IsMatch(parts[0]) || RegexHelper.HostnameOrDomainRegex().IsMatch(parts[0])) &&
int.TryParse(parts[1], out int port) && port > 0 && port <= 65535)
{
serverConnectionInfo = new ServerConnectionInfo(parts[0], port, transportProtocol);
return true;
}
}
// IPv4/hostname
else
{
if (RegexHelper.IPv4AddressRegex().IsMatch(input) || RegexHelper.HostnameOrDomainRegex().IsMatch(input))
{
Debug.WriteLine($"IPv4 or Hostname without port detected. Host: {input}");
serverConnectionInfo = new ServerConnectionInfo(input, defaultPort, transportProtocol);
return true;
}
}
return false;
}
/// <summary>
/// Parses a server connection string into a <see cref="ServerConnectionInfo" /> object.
/// Supports formats: IPv4, IPv4:port, IPv6, [IPv6], [IPv6]:port, hostname, hostname:port
/// </summary>
/// <param name="input">Server connection string to parse.</param>
/// <param name="defaultPort">Default port to use if not specified in input.</param>
/// <returns>Parsed <see cref="ServerConnectionInfo" /> object.</returns>
/// <exception cref="FormatException">Thrown when the input string is not in a valid format.</exception>
public static ServerConnectionInfo Parse(string input, int defaultPort, TransportProtocol transportProtocol)
{
if (TryParse(input, out var serverConnectionInfo, defaultPort, transportProtocol))
return serverConnectionInfo;
throw new FormatException($"Could not parse server connection info from input: {input}");
}
/// <summary>
/// Returns a string that represents the current object. IPv6 addresses are bracketed
/// (<c>[::1]:53</c>) so the address and port remain distinguishable.
/// </summary>
/// <returns>Server:Port, or [Server]:Port for an IPv6 address.</returns>
public override string ToString()
{
return IPAddress.TryParse(Server, out var ip) && ip.AddressFamily == AddressFamily.InterNetworkV6
? $"[{Server}]:{Port}"
: $"{Server}:{Port}";
}
}