DirectTcpProxy.cs 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. using Microsoft;
  2. using Pipelines.Extensions;
  3. using System.IO.Pipelines;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. namespace STUN.Proxy;
  7. public class DirectTcpProxy : ITcpProxy, IDisposableObservable
  8. {
  9. public IPEndPoint? CurrentLocalEndPoint
  10. {
  11. get
  12. {
  13. Verify.NotDisposed(this);
  14. return TcpClient?.Client.LocalEndPoint as IPEndPoint;
  15. }
  16. }
  17. protected TcpClient? TcpClient;
  18. public virtual async ValueTask<IDuplexPipe> ConnectAsync(IPEndPoint local, IPEndPoint dst, CancellationToken cancellationToken = default)
  19. {
  20. Verify.NotDisposed(this);
  21. Requires.NotNull(local, nameof(local));
  22. Requires.NotNull(dst, nameof(dst));
  23. await CloseAsync(cancellationToken);
  24. TcpClient = new TcpClient(local) { NoDelay = true };
  25. await TcpClient.ConnectAsync(dst, cancellationToken);
  26. return TcpClient.Client.AsDuplexPipe();
  27. }
  28. public ValueTask CloseAsync(CancellationToken cancellationToken = default)
  29. {
  30. Verify.NotDisposed(this);
  31. CloseClient();
  32. return default;
  33. }
  34. protected virtual void CloseClient()
  35. {
  36. if (TcpClient is null)
  37. {
  38. return;
  39. }
  40. try
  41. {
  42. TcpClient.Client.Close(0);
  43. }
  44. finally
  45. {
  46. TcpClient.Dispose();
  47. TcpClient = default;
  48. }
  49. }
  50. public bool IsDisposed { get; private set; }
  51. public void Dispose()
  52. {
  53. IsDisposed = true;
  54. CloseClient();
  55. GC.SuppressFinalize(this);
  56. }
  57. }