78 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			78 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using FastGithub.DomainResolve;
 | |
| using Microsoft.AspNetCore.Connections;
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.IO;
 | |
| using System.IO.Pipelines;
 | |
| using System.Net;
 | |
| using System.Net.Sockets;
 | |
| using System.Threading;
 | |
| using System.Threading.Tasks;
 | |
| 
 | |
| namespace FastGithub.HttpServer
 | |
| {
 | |
|     /// <summary>
 | |
|     /// tcp反射代理处理者
 | |
|     /// </summary>
 | |
|     abstract class TcpReverseProxyHandler : ConnectionHandler
 | |
|     {
 | |
|         private readonly IDomainResolver domainResolver;
 | |
|         private readonly DnsEndPoint endPoint;
 | |
|         private readonly TimeSpan connectTimeout = TimeSpan.FromSeconds(10d);
 | |
| 
 | |
|         /// <summary>
 | |
|         /// tcp反射代理处理者
 | |
|         /// </summary>
 | |
|         /// <param name="domainResolver"></param>
 | |
|         /// <param name="endPoint"></param>
 | |
|         public TcpReverseProxyHandler(IDomainResolver domainResolver, DnsEndPoint endPoint)
 | |
|         {
 | |
|             this.domainResolver = domainResolver;
 | |
|             this.endPoint = endPoint;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// tcp连接后
 | |
|         /// </summary>
 | |
|         /// <param name="context"></param>
 | |
|         /// <returns></returns>
 | |
|         public override async Task OnConnectedAsync(ConnectionContext context)
 | |
|         {
 | |
|             var cancellationToken = context.ConnectionClosed;
 | |
|             using var connection = await this.CreateConnectionAsync(cancellationToken);
 | |
|             var task1 = connection.CopyToAsync(context.Transport.Output, cancellationToken);
 | |
|             var task2 = context.Transport.Input.CopyToAsync(connection, cancellationToken);
 | |
|             await Task.WhenAny(task1, task2);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 创建连接
 | |
|         /// </summary>
 | |
|         /// <param name="cancellationToken"></param>
 | |
|         /// <returns></returns>
 | |
|         /// <exception cref="AggregateException"></exception>
 | |
|         private async Task<Stream> CreateConnectionAsync(CancellationToken cancellationToken)
 | |
|         {
 | |
|             var innerExceptions = new List<Exception>();
 | |
|             await foreach (var address in this.domainResolver.ResolveAsync(this.endPoint, cancellationToken))
 | |
|             {
 | |
|                 var socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
 | |
|                 try
 | |
|                 {
 | |
|                     using var timeoutTokenSource = new CancellationTokenSource(this.connectTimeout);
 | |
|                     using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token);
 | |
|                     await socket.ConnectAsync(address, this.endPoint.Port, linkedTokenSource.Token);
 | |
|                     return new NetworkStream(socket, ownsSocket: false);
 | |
|                 }
 | |
|                 catch (Exception ex)
 | |
|                 {
 | |
|                     socket.Dispose();
 | |
|                     cancellationToken.ThrowIfCancellationRequested();
 | |
|                     innerExceptions.Add(ex);
 | |
|                 }
 | |
|             }
 | |
|             throw new AggregateException($"无法连接到{this.endPoint.Host}:{this.endPoint.Port}", innerExceptions);
 | |
|         }
 | |
|     }
 | |
| }
 |