You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

SocketUtil.cs 3.8 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. using System;
  2. using System.Net;
  3. using System.Net.Sockets;
  4. using System.Threading;
  5. namespace Shadowsocks.Util
  6. {
  7. public static class SocketUtil
  8. {
  9. private class DnsEndPoint2 : DnsEndPoint
  10. {
  11. public DnsEndPoint2(string host, int port) : base(host, port)
  12. {
  13. }
  14. public DnsEndPoint2(string host, int port, AddressFamily addressFamily) : base(host, port, addressFamily)
  15. {
  16. }
  17. public override string ToString()
  18. {
  19. return this.Host + ":" + this.Port;
  20. }
  21. }
  22. public static EndPoint GetEndPoint(string host, int port)
  23. {
  24. IPAddress ipAddress;
  25. bool parsed = IPAddress.TryParse(host, out ipAddress);
  26. if (parsed)
  27. {
  28. return new IPEndPoint(ipAddress, port);
  29. }
  30. // maybe is a domain name
  31. return new DnsEndPoint2(host, port);
  32. }
  33. private class AutoReleaseAsyncResult : IAsyncResult
  34. {
  35. public bool IsCompleted { get; } = true;
  36. public WaitHandle AsyncWaitHandle { get; } = null;
  37. public object AsyncState { get; set; }
  38. public bool CompletedSynchronously { get; } = true;
  39. public TcpUserToken UserToken { get; set; }
  40. ~AutoReleaseAsyncResult()
  41. {
  42. UserToken.Dispose();
  43. }
  44. }
  45. private class TcpUserToken
  46. {
  47. public AsyncCallback Callback { get; private set; }
  48. public SocketAsyncEventArgs Args { get; private set; }
  49. public object AsyncState { get; private set; }
  50. public TcpUserToken(AsyncCallback callback, object state, SocketAsyncEventArgs args)
  51. {
  52. Callback = callback;
  53. AsyncState = state;
  54. Args = args;
  55. }
  56. public void Dispose()
  57. {
  58. Args?.Dispose();
  59. Callback = null;
  60. Args = null;
  61. AsyncState = null;
  62. }
  63. }
  64. private static void OnTcpConnectCompleted(object sender, SocketAsyncEventArgs args)
  65. {
  66. args.Completed -= OnTcpConnectCompleted;
  67. TcpUserToken token = (TcpUserToken) args.UserToken;
  68. AutoReleaseAsyncResult r = new AutoReleaseAsyncResult
  69. {
  70. AsyncState = token.AsyncState,
  71. UserToken = token
  72. };
  73. token.Callback(r);
  74. }
  75. public static void BeginConnectTcp(EndPoint endPoint, AsyncCallback callback, object state)
  76. {
  77. var arg = new SocketAsyncEventArgs();
  78. arg.RemoteEndPoint = endPoint;
  79. arg.Completed += OnTcpConnectCompleted;
  80. arg.UserToken = new TcpUserToken(callback, state, arg);
  81. Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg);
  82. }
  83. public static Socket EndConnectTcp(IAsyncResult asyncResult)
  84. {
  85. var r = asyncResult as AutoReleaseAsyncResult;
  86. if (r == null)
  87. {
  88. throw new ArgumentException("Invalid asyncResult.", nameof(asyncResult));
  89. }
  90. var tut = r.UserToken;
  91. var arg = tut.Args;
  92. if (arg.SocketError != SocketError.Success)
  93. {
  94. if (arg.ConnectByNameError != null)
  95. {
  96. throw arg.ConnectByNameError;
  97. }
  98. var ex = new SocketException((int)arg.SocketError);
  99. throw ex;
  100. }
  101. var so = tut.Args.ConnectSocket;
  102. so.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
  103. return so;
  104. }
  105. }
  106. }