175 lines
6.4 KiB
C#
175 lines
6.4 KiB
C#
using System;
|
||
using System.Linq;
|
||
using System.Net.Sockets;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using Ultron.Proxy.Interfaces;
|
||
using Ultron.Proxy.Models;
|
||
|
||
namespace Ultron.Proxy
|
||
{
|
||
public class Router
|
||
{
|
||
CancellationTokenSource CANCEL_TOKEN = new CancellationTokenSource();
|
||
CancellationTokenSource TRANSFERING_TOKEN = new CancellationTokenSource();
|
||
ServerConnnectionManager ConnnectionManager;
|
||
|
||
internal static Config ClientConfig;
|
||
|
||
//inject
|
||
internal static ILogger Logger;
|
||
|
||
public Router(ILogger logger)
|
||
{
|
||
Logger = logger;
|
||
}
|
||
|
||
public void SetConifiguration(Config config)
|
||
{
|
||
ClientConfig = config;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重要:连接服务端
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public async Task ConnectToProvider()
|
||
{
|
||
var appIdIpPortConfig = ClientConfig.Clients;
|
||
|
||
ConnnectionManager = ServerConnnectionManager.Create();
|
||
ConnnectionManager.ClientGroupConnected += ServerConnnectionManager_ClientGroupConnected;
|
||
var clientModel = await ConnnectionManager.InitConfig();
|
||
int counter = 0;
|
||
//appid为0时说明没有分配appid,所以需要分配一个
|
||
foreach (var app in appIdIpPortConfig)
|
||
{
|
||
if (app.AppID == 0)
|
||
{
|
||
app.AppID = clientModel.AppList[counter].AppId;
|
||
counter++;
|
||
}
|
||
}
|
||
Logger.Debug("****************port list*************");
|
||
|
||
foreach (var ap in clientModel.AppList)
|
||
{
|
||
var cApp = appIdIpPortConfig.First(obj => obj.AppID == ap.AppId);
|
||
Logger.Debug(ap.AppId.ToString() + ": " + ClientConfig.ProviderAddress + ":" + ap.Port.ToString() + "=>" +
|
||
cApp.IP + ":" + cApp.Port);
|
||
}
|
||
Logger.Debug("**************************************");
|
||
Task pollingTask = ConnnectionManager.PollingToProvider();
|
||
try
|
||
{
|
||
await pollingTask;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logger.Error("Thread:" + Thread.CurrentThread.ManagedThreadId + " crashed.\n", ex);
|
||
throw;
|
||
}
|
||
|
||
await Task.Delay(TimeSpan.FromHours(24), CANCEL_TOKEN.Token);
|
||
}
|
||
|
||
private void ServerConnnectionManager_ClientGroupConnected(object sender, EventArgs e)
|
||
{
|
||
var args = (ClientGroupEventArgs)e;
|
||
foreach (TcpClient providerClient in args.NewClients)
|
||
{
|
||
|
||
Router.Logger.Debug("Open server connection.");
|
||
OpenTrasferation(args.App.AppId, providerClient);
|
||
}
|
||
|
||
}
|
||
|
||
private async Task OpenTrasferation(int appId, TcpClient providerClient)
|
||
{
|
||
try
|
||
{
|
||
byte[] buffer = new byte[1];
|
||
NetworkStream providerClientStream = providerClient.GetStream();
|
||
//接收首条消息,首条消息中返回的是appid和客户端
|
||
int readByteCount = await providerClientStream.ReadAsync(buffer, 0, buffer.Length);
|
||
//从空闲连接列表中移除
|
||
ConnnectionManager.RemoveClient(appId, providerClient);
|
||
//每移除一个链接则发起一个新的链接
|
||
Logger.Debug(appId + "接收到连接请求");
|
||
TcpClient toTargetServer = new TcpClient();
|
||
//根据clientid_appid发送到固定的端口
|
||
ClientApp item = ClientConfig.Clients.First((obj) => obj.AppID == appId);
|
||
|
||
//只发送一次,需要在链接成功移除时加入
|
||
await ConnnectionManager.ConnectAppToServer(appId);
|
||
Logger.Debug("已建立反向连接:" + appId);
|
||
// item1:app编号,item2:ip地址,item3:目标服务端口
|
||
toTargetServer.Connect(item.IP, item.Port);
|
||
Logger.Debug("已连接目标服务:" + item.IP.ToString() + ":" + item.Port.ToString());
|
||
|
||
NetworkStream targetServerStream = toTargetServer.GetStream();
|
||
//targetServerStream.Write(buffer, 0, readByteCount);
|
||
TcpTransferAsync(providerClientStream, targetServerStream, providerClient, toTargetServer);
|
||
//already close connection
|
||
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Logger.Debug(e);
|
||
throw;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
private async Task TcpTransferAsync(NetworkStream providerStream, NetworkStream targetServceStream, TcpClient providerClient, TcpClient toTargetServer)
|
||
{
|
||
try
|
||
{
|
||
Logger.Debug("Looping start.");
|
||
//创建相互转发流
|
||
var taskT2PLooping = ToStaticTransfer(TRANSFERING_TOKEN.Token, targetServceStream, providerStream, "T2P");
|
||
var taskP2TLooping = StreamTransfer(TRANSFERING_TOKEN.Token, providerStream, targetServceStream, "P2T");
|
||
|
||
//close connnection,whether client or server stopped transferring.
|
||
var comletedTask = await Task.WhenAny(taskT2PLooping, taskP2TLooping);
|
||
//Router.Logger.Debug(comletedTask.Result + "传输关闭,重新读取字节");
|
||
providerClient.Close();
|
||
Logger.Debug("已关闭toProvider连接。");
|
||
toTargetServer.Close();
|
||
Logger.Debug("已关闭toTargetServer连接。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logger.Debug(ex.ToString());
|
||
throw;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
private async Task<string> StreamTransfer(CancellationToken ct, NetworkStream fromStream, NetworkStream toStream, string signal, Func<byte[], Task<bool>> beforeTransfer = null)
|
||
{
|
||
await fromStream.CopyToAsync(toStream, 4096, ct);
|
||
return signal;
|
||
}
|
||
|
||
|
||
private async Task<string> ToStaticTransfer(CancellationToken ct, NetworkStream fromStream, NetworkStream toStream, string signal, Func<byte[], Task<bool>> beforeTransfer = null)
|
||
{
|
||
|
||
await fromStream.CopyToAsync(toStream, 4096, ct);
|
||
return signal;
|
||
}
|
||
|
||
private void SendZero(int port)
|
||
{
|
||
TcpClient tc = new TcpClient();
|
||
tc.Connect("127.0.0.1", port);
|
||
tc.Client.Send(new byte[] { 0 });
|
||
}
|
||
}
|
||
|
||
}
|