HostnameEndpoint.cs 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. using System;
  2. using System.Diagnostics.CodeAnalysis;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. namespace STUN
  6. {
  7. public class HostnameEndpoint
  8. {
  9. public string Hostname { get; }
  10. public ushort Port { get; }
  11. private HostnameEndpoint(string host, ushort port)
  12. {
  13. Hostname = host;
  14. Port = port;
  15. }
  16. public static bool TryParse(string s, [NotNullWhen(true)] out HostnameEndpoint? result, ushort defaultPort = 0)
  17. {
  18. result = null;
  19. if (string.IsNullOrEmpty(s))
  20. {
  21. return false;
  22. }
  23. var hostLength = s.Length;
  24. var pos = s.LastIndexOf(':');
  25. if (pos > 0)
  26. {
  27. if (s[pos - 1] is ']')
  28. {
  29. hostLength = pos;
  30. }
  31. else if (s.AsSpan(0, pos).LastIndexOf(':') is -1)
  32. {
  33. hostLength = pos;
  34. }
  35. }
  36. var host = s[..hostLength];
  37. var type = Uri.CheckHostName(host);
  38. switch (type)
  39. {
  40. case UriHostNameType.Dns:
  41. case UriHostNameType.IPv4:
  42. case UriHostNameType.IPv6:
  43. {
  44. break;
  45. }
  46. default:
  47. {
  48. return false;
  49. }
  50. }
  51. if (hostLength == s.Length || ushort.TryParse(s.AsSpan(hostLength + 1), out defaultPort))
  52. {
  53. result = new HostnameEndpoint(host, defaultPort);
  54. return true;
  55. }
  56. return false;
  57. }
  58. public override string ToString()
  59. {
  60. if (IPAddress.TryParse(Hostname, out var ip) && ip.AddressFamily is AddressFamily.InterNetworkV6)
  61. {
  62. return $@"[{ip}]:{Port}";
  63. }
  64. return $@"{Hostname}:{Port}";
  65. }
  66. }
  67. }