增加打洞和中继插件,后续桌面共享的代理将有这两个插件去实现通信

This commit is contained in:
snltty
2024-05-02 19:54:58 +08:00
parent a98a92d88b
commit 866f12a4af
35 changed files with 800 additions and 368 deletions

View File

@@ -0,0 +1,5 @@
import { sendWebsocketMsg } from './request'
export const updateRelayConnect = (machineName) => {
return sendWebsocketMsg('relay/Connect', machineName);
}

View File

@@ -0,0 +1,21 @@
import { sendWebsocketMsg } from './request'
export const getConfig = () => {
return sendWebsocketMsg('signInclient/config');
}
export const updateConfigSet = (data) => {
return sendWebsocketMsg('signInclient/set', data);
}
export const updateConfigSetServers = (servers) => {
return sendWebsocketMsg('signInclient/setservers', servers);
}
export const getSignInfo = () => {
return sendWebsocketMsg('signInclient/info');
}
export const getSignList = (data) => {
return sendWebsocketMsg('signInclient/List', data);
}
export const updateSignInDel = (machineName) => {
return sendWebsocketMsg('signInclient/del', machineName);
}

View File

@@ -1,25 +1,5 @@
import { sendWebsocketMsg } from './request'
export const getConfig = () => {
return sendWebsocketMsg('tunnel/config');
}
export const updateConfigSet = (data) => {
return sendWebsocketMsg('tunnel/configset', data);
}
export const updateConfigSetServers = (servers) => {
return sendWebsocketMsg('tunnel/configsetservers', servers);
}
export const getSignInfo = () => {
return sendWebsocketMsg('tunnel/signininfo');
}
export const getSignList = (data) => {
return sendWebsocketMsg('tunnel/SignInList', data);
}
export const updateSignInDel = (machineName) => {
return sendWebsocketMsg('tunnel/signindel', machineName);
}
export const updateTunnelConnect = (machineName) => {
return sendWebsocketMsg('tunnel/TunnelConnect', machineName);
return sendWebsocketMsg('tunnel/Connect', machineName);
}

View File

@@ -34,7 +34,7 @@
<script>
import { computed, onMounted, reactive, watch } from 'vue';
import { initWebsocket, subWebsocketState } from '../apis/request'
import { getConfig,getSignInfo } from '../apis/tunnel'
import { getConfig,getSignInfo } from '../apis/signin'
import { useRoute } from 'vue-router';
import { injectGlobalData } from '../provide';
export default {
@@ -65,12 +65,14 @@ export default {
const _getConfig = ()=>{
getConfig().then((res)=>{
console.log(res);
globalData.value.config.Common = res.Data.Common;
globalData.value.config.Client = res.Data.Client;
setTimeout(()=>{
_getConfig();
},1000);
}).catch((err)=>{
console.log(err);
setTimeout(()=>{
_getConfig();
},1000);

View File

@@ -75,7 +75,7 @@
</el-dialog>
</template>
<script>
import { updateConfigSet, updateConfigSetServers } from '@/apis/tunnel';
import { updateConfigSet, updateConfigSetServers } from '@/apis/signin';
import { injectGlobalData } from '@/provide';
import { ElMessage } from 'element-plus';
import { computed, reactive } from 'vue';

View File

@@ -15,9 +15,9 @@ import 'element-plus/theme-chalk/display.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
import {
ChromeFilled,
ArrowDown,
} from '@element-plus/icons-vue'
app.component(ChromeFilled.name, ChromeFilled);
app.component(ArrowDown.name, ArrowDown);
app.use(ElementPlus, { size: 'default' }).use(router).mount('#app');

View File

@@ -18,8 +18,18 @@
<el-table-column prop="LastSignIn" label="最后登入" width="140" />
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" @click="handleTestTunnel(scope.row.MachineName)">测试</el-button>
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消" title="删除不可逆,是否确认?" @confirm="handleDelTunnel(scope.row.MachineName)">
<el-dropdown>
<el-button size="small">
测试<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleTestTunnel(scope.row.MachineName)">打洞</el-dropdown-item>
<el-dropdown-item @click="handleTestRelay(scope.row.MachineName)">中继</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消" title="删除不可逆,是否确认?" @confirm="handleDel(scope.row.MachineName)">
<template #reference>
<el-button type="danger" size="small">删除</el-button>
</template>
@@ -37,7 +47,9 @@
</div>
</template>
<script>
import {getSignList,updateTunnelConnect,updateSignInDel} from '@/apis/tunnel.js'
import {getSignList,updateSignInDel} from '@/apis/signin.js'
import {updateTunnelConnect} from '@/apis/tunnel.js'
import {updateRelayConnect} from '@/apis/relay.js'
import {subWebsocketState} from '@/apis/request.js'
import {injectGlobalData} from '../provide.js'
import {reactive,onMounted, ref, nextTick, onUnmounted} from 'vue'
@@ -73,7 +85,10 @@ export default {
const handleTestTunnel = (name)=>{
updateTunnelConnect(name);
}
const handleDelTunnel = (name)=>{
const handleTestRelay = (name)=>{
updateRelayConnect(name);
}
const handleDel = (name)=>{
updateSignInDel(name).then(()=>{
_getSignList();
});
@@ -89,7 +104,7 @@ export default {
});
return {
state,wrap,handlePageChange,handleTestTunnel,handleDelTunnel
state,wrap,handlePageChange,handleTestTunnel,handleTestRelay,handleDel
}
}
}

View File

@@ -1,11 +1,11 @@
import { sendWebsocketMsg } from './request'
export const getList = (groupid) => {
return sendWebsocketMsg('signin/list', groupid);
return sendWebsocketMsg('signinserver/list', groupid);
}
export const getConfig = () => {
return sendWebsocketMsg('signin/config');
return sendWebsocketMsg('signinserver/config');
}
export const delDevice = (name) => {
return sendWebsocketMsg('signin/del', name);
return sendWebsocketMsg('signinserver/del', name);
}

View File

@@ -102,7 +102,7 @@ namespace cmonitor.config
{
"cmonitor.client.","cmonitor.server.","cmonitor.serializes.",
"cmonitor.plugins.signin.", "cmonitor.plugins.watch.","cmonitor.plugins.devices.","cmonitor.plugins.report.",
"cmonitor.plugins.share.","cmonitor.plugins.rule.","cmonitor.plugins.modes.",
"cmonitor.plugins.share.","cmonitor.plugins.rule.","cmonitor.plugins.modes.","cmonitor.plugins.tunnel.","cmonitor.plugins.relay",
}).Distinct().ToArray();
}
}

View File

@@ -0,0 +1,77 @@
using cmonitor.client.api;
using cmonitor.config;
using cmonitor.plugins.relay.transport;
using common.libs;
using common.libs.api;
using common.libs.extends;
using System.Text;
namespace cmonitor.plugins.relay
{
public sealed class RelayApiController : IApiClientController
{
private readonly Config config;
private readonly RelayTransfer relayTransfer;
public RelayApiController(Config config, RelayTransfer relayTransfer)
{
this.config = config;
this.relayTransfer = relayTransfer;
RelayTest();
}
public void Connect(ApiControllerParamsInfo param)
{
Task.Run(async () =>
{
try
{
RelayTransportState state = await relayTransfer.ConnectAsync(param.Content, "test", config.Data.Client.Relay.SecretKey);
if (state != null)
{
var socket = state.Socket;
for (int i = 0; i < 10; i++)
{
Logger.Instance.Debug($"relay [test] send {i}");
socket.Send(Encoding.UTF8.GetBytes($"snltty.relay.{i}"));
await Task.Delay(10);
}
socket.SafeClose();
}
}
catch (Exception ex)
{
Console.WriteLine(ex + "");
}
});
}
private void RelayTest()
{
relayTransfer.OnConnected += (RelayTransportState state) =>
{
if (state.Info.TransactionId == "test")
{
Task.Run(() =>
{
byte[] bytes = new byte[1024];
while (true)
{
int length = state.Socket.Receive(bytes);
if (length == 0) break;
Logger.Instance.Debug($"relay [{state.Info.TransactionId}] receive {Encoding.UTF8.GetString(bytes.AsSpan(0,length))}");
}
});
}
};
}
}
public sealed class ConfigSetInfo
{
public string Name { get; set; }
public string GroupId { get; set; }
public string Server { get; set; }
}
}

View File

@@ -0,0 +1,45 @@
using cmonitor.config;
using cmonitor.plugins.relay.messenger;
using cmonitor.plugins.relay.transport;
using cmonitor.startup;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace cmonitor.plugins.relay
{
public sealed class RelayStartup : IStartup
{
public StartupLevel Level => StartupLevel.Normal;
public void AddClient(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<RelayApiController>();
serviceCollection.AddSingleton<RelayClientMessenger>();
serviceCollection.AddSingleton<TransportSelfHost>();
serviceCollection.AddSingleton<RelayTransfer>();
if (config.Data.Client.Relay.Servers.Length == 0)
{
config.Data.Client.Relay.Servers = new RelayCompactInfo[]
{
new RelayCompactInfo{ Name="self", Disabled = false, Host = config.Data.Client.Server }
};
}
}
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<RelayServerMessenger>();
}
public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
RelayTransfer relayTransfer = serviceProvider.GetService<RelayTransfer>();
relayTransfer.Load(assemblies);
}
public void UseServer(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
}
}
}

View File

@@ -0,0 +1,90 @@
using cmonitor.client;
using cmonitor.config;
using cmonitor.plugins.relay.transport;
using cmonitor.server;
using common.libs;
using common.libs.extends;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
namespace cmonitor.plugins.relay
{
public sealed class RelayTransfer
{
private List<ITransport> transports;
private readonly Config config;
private readonly ServiceProvider serviceProvider;
public Action<RelayTransportState> OnConnected { get; set; } = (state) => { };
public RelayTransfer(Config config, ServiceProvider serviceProvider)
{
this.config = config;
this.serviceProvider = serviceProvider;
}
public void Load(Assembly[] assembs)
{
IEnumerable<Type> types = ReflectionHelper.GetInterfaceSchieves(assembs, typeof(ITransport));
types = config.Data.Common.PluginContains(types);
transports = types.Select(c => (ITransport)serviceProvider.GetService(c)).Where(c => c != null).Where(c => string.IsNullOrWhiteSpace(c.Name) == false).ToList();
Logger.Instance.Warning($"load relay transport:{string.Join(",", transports.Select(c => c.Name))}");
}
public async Task<RelayTransportState> ConnectAsync(string remoteMachineName, string transactionId, string secretKey)
{
IEnumerable<ITransport> _transports = transports.OrderBy(c => c.Name);
foreach (RelayCompactInfo item in config.Data.Client.Relay.Servers.Where(c=>c.Disabled == false))
{
ITransport transport = _transports.FirstOrDefault(c => c.Name == item.Name);
if (transport == null)
{
continue;
}
try
{
IPEndPoint server = NetworkHelper.GetEndPoint(item.Host, 3478);
RelayInfo relayInfo = new RelayInfo
{
FlowingId = 0,
RemoteMachineName = remoteMachineName,
SecretKey = secretKey,
Server = server,
TransactionId = transactionId,
TransportName = transport.Name
};
Socket socket = await transport.RelayAsync(relayInfo);
if (socket != null)
{
return new RelayTransportState { Info = relayInfo, Socket = socket };
}
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
}
}
return null;
}
public async Task<bool> OnBeginAsync(RelayInfo relayInfo)
{
ITransport _transports = transports.FirstOrDefault(c => c.Name == relayInfo.TransportName);
if (_transports != null)
{
Socket socket = await _transports.OnBeginAsync(relayInfo);
if (socket != null)
{
OnConnected(new RelayTransportState { Info = relayInfo, Socket = socket });
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,29 @@
namespace cmonitor.config
{
public partial class ConfigClientInfo
{
public RelayConfigClientInfo Relay { get; set; } = new RelayConfigClientInfo();
}
public partial class ConfigServerInfo
{
public RelayConfigServerInfo Relay { get; set; } = new RelayConfigServerInfo();
}
public sealed class RelayConfigClientInfo
{
public RelayCompactInfo[] Servers { get; set; } = Array.Empty<RelayCompactInfo>();
public string SecretKey { get; set; } = "snltty";
}
public sealed class RelayConfigServerInfo
{
public string SecretKey { get; set; } = "snltty";
}
public sealed class RelayCompactInfo
{
public string Name { get; set; }
public string Host { get; set; }
public bool Disabled { get; set; }
}
}

View File

@@ -0,0 +1,112 @@
using cmonitor.config;
using cmonitor.plugins.relay.transport;
using cmonitor.plugins.signin.messenger;
using cmonitor.server;
using common.libs;
using MemoryPack;
using System.Collections.Concurrent;
using System.Net.Sockets;
using System.Text;
namespace cmonitor.plugins.relay.messenger
{
public sealed class RelayClientMessenger : IMessenger
{
private readonly RelayTransfer relayTransfer;
public RelayClientMessenger(RelayTransfer relayTransfer)
{
this.relayTransfer = relayTransfer;
}
[MessengerId((ushort)RelayMessengerIds.Relay)]
public async Task Relay(IConnection connection)
{
RelayInfo info = MemoryPackSerializer.Deserialize<RelayInfo>(connection.ReceiveRequestWrap.Payload.Span);
bool res = await relayTransfer.OnBeginAsync(info);
connection.Write(res ? Helper.TrueArray : Helper.FalseArray);
}
}
public sealed class RelayServerMessenger : IMessenger
{
private readonly Config config;
private readonly MessengerSender messengerSender;
private readonly SignCaching signCaching;
private readonly ConcurrentDictionary<ulong, TaskCompletionSource<IConnection>> dic = new ConcurrentDictionary<ulong, TaskCompletionSource<IConnection>>();
private ulong flowingId = 0;
public RelayServerMessenger(Config config, MessengerSender messengerSender, SignCaching signCaching)
{
this.config = config;
this.messengerSender = messengerSender;
this.signCaching = signCaching;
}
[MessengerId((ushort)RelayMessengerIds.RelayForward)]
public async Task RelayForward(IConnection connection)
{
RelayInfo info = MemoryPackSerializer.Deserialize<RelayInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (info.FlowingId == 0)
{
if (info.SecretKey != config.Data.Client.Relay.SecretKey)
{
connection.Write(Helper.FalseArray);
return;
}
if (signCaching.Get(info.RemoteMachineName, out SignCacheInfo cache) == false)
{
connection.Write(Helper.FalseArray);
return;
}
info.FlowingId = Interlocked.Increment(ref flowingId);
TaskCompletionSource<IConnection> tcs = new TaskCompletionSource<IConnection>();
dic.TryAdd(info.FlowingId, tcs);
try
{
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = cache.Connection,
MessengerId = (ushort)RelayMessengerIds.Relay,
Payload = MemoryPackSerializer.Serialize(info)
});
if (resp.Code != MessageResponeCodes.OK || resp.Data.Span.SequenceEqual(Helper.TrueArray) == false)
{
connection.Write(Helper.FalseArray);
return;
}
IConnection targetConnection = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(3000));
connection.TcpTargetSocket = targetConnection.TcpSourceSocket;
targetConnection.TcpTargetSocket = connection.TcpSourceSocket;
connection.Write(Helper.TrueArray);
}
catch (Exception)
{
connection.Write(Helper.FalseArray);
}
finally
{
dic.TryRemove(info.FlowingId, out _);
}
}
else
{
if (dic.TryRemove(info.FlowingId, out TaskCompletionSource<IConnection> tcs))
{
tcs.SetResult(connection);
connection.Write(Helper.TrueArray);
}
else
{
connection.Write(Helper.FalseArray);
}
return;
}
}
}
}

View File

@@ -0,0 +1,12 @@
namespace cmonitor.plugins.relay.messenger
{
public enum RelayMessengerIds : ushort
{
Update = 2100,
Relay = 2101,
RelayForward = 2102,
None = 2199
}
}

View File

@@ -0,0 +1,38 @@
using cmonitor.plugins.relay.messenger;
using MemoryPack;
using System.Net;
using System.Net.Sockets;
using System.Text.Json.Serialization;
namespace cmonitor.plugins.relay.transport
{
public interface ITransport
{
public string Name { get; }
public Task<Socket> RelayAsync(RelayInfo relayInfo);
public Task<Socket> OnBeginAsync(RelayInfo relayInfo);
}
[MemoryPackable]
public sealed partial class RelayInfo
{
public string RemoteMachineName { get; set; }
public string TransactionId { get; set; }
public string SecretKey { get; set; }
public string TransportName { get; set; }
public ulong FlowingId { get; set; }
[MemoryPackAllowSerialize]
public IPEndPoint Server { get; set; }
}
public sealed class RelayTransportState
{
public RelayInfo Info { get; set; }
public Socket Socket { get; set; }
}
}

View File

@@ -0,0 +1,73 @@
using cmonitor.plugins.relay.messenger;
using cmonitor.server;
using common.libs;
using common.libs.extends;
using MemoryPack;
using System.Net.Sockets;
using System.Text;
namespace cmonitor.plugins.relay.transport
{
public sealed class TransportSelfHost : ITransport
{
public string Name => "self";
private readonly TcpServer tcpServer;
private readonly MessengerSender messengerSender;
private readonly Memory<byte> relayFlagData = Encoding.UTF8.GetBytes("snltty.relay").AsMemory();
public TransportSelfHost(TcpServer tcpServer, MessengerSender messengerSender)
{
this.tcpServer = tcpServer;
this.messengerSender = messengerSender;
}
public async Task<Socket> RelayAsync(RelayInfo relayInfo)
{
Socket socket = new Socket(relayInfo.Server.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Reuse(true);
socket.IPv6Only(relayInfo.Server.AddressFamily, false);
await socket.ConnectAsync(relayInfo.Server).WaitAsync(TimeSpan.FromSeconds(5));
IConnection connection = tcpServer.BindReceive(socket);
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = connection,
MessengerId = (ushort)RelayMessengerIds.RelayForward,
Payload = MemoryPackSerializer.Serialize(relayInfo)
});
if (resp.Code != MessageResponeCodes.OK || resp.Data.Span.SequenceEqual(Helper.TrueArray) == false)
{
connection.Disponse();
return null;
}
await socket.SendAsync(relayFlagData);
await Task.Delay(10);
return socket;
}
public async Task<Socket> OnBeginAsync(RelayInfo relayInfo)
{
Socket socket = new Socket(relayInfo.Server.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Reuse(true);
socket.IPv6Only(relayInfo.Server.AddressFamily, false);
await socket.ConnectAsync(relayInfo.Server).WaitAsync(TimeSpan.FromSeconds(5));
IConnection connection = tcpServer.BindReceive(socket);
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = connection,
MessengerId = (ushort)RelayMessengerIds.RelayForward,
Payload = MemoryPackSerializer.Serialize(relayInfo)
});
if (resp.Code != MessageResponeCodes.OK || resp.Data.Span.SequenceEqual(Helper.TrueArray) == false)
{
connection.Disponse();
return null;
}
await socket.SendAsync(relayFlagData);
await Task.Delay(10);
return socket;
}
}
}

View File

@@ -2,14 +2,19 @@
using cmonitor.config;
using cmonitor.plugins.signin.messenger;
using common.libs.api;
using cmonitor.client.api;
using common.libs.extends;
using cmonitor.client;
using cmonitor.server;
using MemoryPack;
namespace cmonitor.plugins.signin
{
public sealed class SignInApiController : IApiServerController
public sealed class SignInServerApiController : IApiServerController
{
private readonly SignCaching signCaching;
private readonly Config config;
public SignInApiController(SignCaching signCaching, Config config)
public SignInServerApiController(SignCaching signCaching, Config config)
{
this.signCaching = signCaching;
this.config = config;
@@ -31,4 +36,77 @@ namespace cmonitor.plugins.signin
return config;
}
}
public sealed class SignInClientApiController : IApiClientController
{
private readonly Config config;
private readonly ClientSignInState clientSignInState;
private readonly ClientSignInTransfer clientSignInTransfer;
private readonly MessengerSender messengerSender;
public SignInClientApiController(Config config, ClientSignInState clientSignInState, ClientSignInTransfer clientSignInTransfer, MessengerSender messengerSender)
{
this.config = config;
this.clientSignInState = clientSignInState;
this.clientSignInTransfer = clientSignInTransfer;
this.messengerSender = messengerSender;
}
public Config Config(ApiControllerParamsInfo param)
{
return config;
}
public void Set(ApiControllerParamsInfo param)
{
ConfigSetInfo info = param.Content.DeJson<ConfigSetInfo>();
config.Data.Client.Name = info.Name;
config.Data.Client.GroupId = info.GroupId;
config.Data.Client.Server = info.Server;
config.Save();
clientSignInTransfer.SignOut();
_ = clientSignInTransfer.SignIn();
}
public void SetServers(ApiControllerParamsInfo param)
{
config.Data.Client.Servers = param.Content.DeJson<ClientServerInfo[]>();
config.Save();
}
public ClientSignInState Info(ApiControllerParamsInfo param)
{
return clientSignInState;
}
public async Task Del(ApiControllerParamsInfo param)
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)SignInMessengerIds.Delete,
Payload = MemoryPackSerializer.Serialize(param.Content)
});
}
public async Task<SignInListResponseInfo> List(ApiControllerParamsInfo param)
{
SignInListRequestInfo request = param.Content.DeJson<SignInListRequestInfo>();
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)SignInMessengerIds.List,
Payload = MemoryPackSerializer.Serialize(request)
});
if (resp.Code == MessageResponeCodes.OK)
{
return MemoryPackSerializer.Deserialize<SignInListResponseInfo>(resp.Data.Span);
}
return new SignInListResponseInfo { };
}
}
public sealed class ConfigSetInfo
{
public string Name { get; set; }
public string GroupId { get; set; }
public string Server { get; set; }
}
}

View File

@@ -12,13 +12,15 @@ namespace cmonitor.plugins.signin
public void AddClient(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<SignInClientApiController>();
}
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<SignCaching>();
serviceCollection.AddSingleton<SignInMessenger>();
serviceCollection.AddSingleton<SignInApiController>();
serviceCollection.AddSingleton<SignInServerApiController>();
}
public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)

View File

@@ -16,80 +16,23 @@ namespace cmonitor.plugins.tunnel
{
public sealed class TunnelApiController : IApiClientController
{
private readonly Config config;
private readonly ClientSignInState clientSignInState;
private readonly ClientSignInTransfer clientSignInTransfer;
private readonly MessengerSender messengerSender;
private readonly TunnelTransfer tunnelTransfer;
private readonly TunnelBindServer tunnelBindServer;
public TunnelApiController(Config config, ClientSignInState clientSignInState, ClientSignInTransfer clientSignInTransfer, MessengerSender messengerSender, TunnelTransfer tunnelTransfer,
public TunnelApiController(TunnelTransfer tunnelTransfer,
TunnelBindServer tunnelBindServer)
{
this.config = config;
this.clientSignInState = clientSignInState;
this.clientSignInTransfer = clientSignInTransfer;
this.messengerSender = messengerSender;
this.tunnelTransfer = tunnelTransfer;
this.tunnelBindServer = tunnelBindServer;
TunnelTest();
}
public Config Config(ApiControllerParamsInfo param)
{
return config;
}
public void ConfigSet(ApiControllerParamsInfo param)
{
ConfigSetInfo info = param.Content.DeJson<ConfigSetInfo>();
config.Data.Client.Name = info.Name;
config.Data.Client.GroupId = info.GroupId;
config.Data.Client.Server = info.Server;
config.Save();
clientSignInTransfer.SignOut();
_ = clientSignInTransfer.SignIn();
}
public void ConfigSetServers(ApiControllerParamsInfo param)
{
config.Data.Client.Servers = param.Content.DeJson<ClientServerInfo[]>();
config.Save();
}
public ClientSignInState SignInInfo(ApiControllerParamsInfo param)
{
return clientSignInState;
}
public async Task SignInDel(ApiControllerParamsInfo param)
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)SignInMessengerIds.Delete,
Payload = MemoryPackSerializer.Serialize(param.Content)
});
}
public async Task<SignInListResponseInfo> SignInList(ApiControllerParamsInfo param)
{
SignInListRequestInfo request = param.Content.DeJson<SignInListRequestInfo>();
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)SignInMessengerIds.List,
Payload = MemoryPackSerializer.Serialize(request)
});
if (resp.Code == MessageResponeCodes.OK)
{
return MemoryPackSerializer.Deserialize<SignInListResponseInfo>(resp.Data.Span);
}
return new SignInListResponseInfo { };
}
public Dictionary<string, TunnelConnectInfo> TunnelConnections(ApiControllerParamsInfo param)
public Dictionary<string, TunnelConnectInfo> Connections(ApiControllerParamsInfo param)
{
return tunnelTransfer.Connections;
}
public void TunnelConnect(ApiControllerParamsInfo param)
public void Connect(ApiControllerParamsInfo param)
{
Task.Run(async () =>
{
@@ -129,10 +72,4 @@ namespace cmonitor.plugins.tunnel
}
}
public sealed class ConfigSetInfo
{
public string Name { get; set; }
public string GroupId { get; set; }
public string Server { get; set; }
}
}

View File

@@ -34,11 +34,18 @@ namespace cmonitor.plugins.tunnel
Logger.Instance.Info($"tunnel route level getting.");
config.Data.Client.Tunnel.RouteLevel = NetworkHelper.GetRouteLevel(out List<IPAddress> ips);
Logger.Instance.Info($"tunnel route level:{config.Data.Client.Tunnel.RouteLevel}");
if (config.Data.Client.Tunnel.Servers.Length == 0)
{
config.Data.Client.Tunnel.Servers = new TunnelCompactInfo[]
{
new TunnelCompactInfo{ Name="self", Disabled = false, Host = config.Data.Client.Server }
};
}
}
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<TunnelExternalIPServer>();
serviceCollection.AddSingleton<TunnelServerMessenger>();
}
@@ -53,10 +60,7 @@ namespace cmonitor.plugins.tunnel
public void UseServer(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
Logger.Instance.Info($"use tunnel external ip server in server mode.");
TunnelExternalIPServer tunnelServer = serviceProvider.GetService<TunnelExternalIPServer>();
tunnelServer.Start(config.Data.Server.Tunnel.ListenPort);
Logger.Instance.Info($"start tunnel external ip server, port : {config.Data.Server.Tunnel.ListenPort}");
}
}
}

View File

@@ -70,7 +70,6 @@ namespace cmonitor.plugins.tunnel
{
continue;
}
TunnelTransportInfo tunnelTransportInfo = new TunnelTransportInfo
{
Direction = TunnelTransportDirection.Forward,
@@ -80,7 +79,6 @@ namespace cmonitor.plugins.tunnel
Local = localInfo,
Remote = remoteInfo,
};
TunnelTransportState state = await transport.ConnectAsync(tunnelTransportInfo);
if (state != null)
{
@@ -148,18 +146,19 @@ namespace cmonitor.plugins.tunnel
}
private async Task OnSendConnectBegin(TunnelTransportInfo tunnelTransportInfo)
private async Task<bool> OnSendConnectBegin(TunnelTransportInfo tunnelTransportInfo)
{
await messengerSender.SendReply(new MessageRequestWrap
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)TunnelMessengerIds.BeginForward,
Payload = MemoryPackSerializer.Serialize(tunnelTransportInfo)
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
private async Task OnSendConnectFail(TunnelTransportInfo tunnelTransportInfo)
{
await messengerSender.SendReply(new MessageRequestWrap
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)TunnelMessengerIds.FailForward,
@@ -185,9 +184,9 @@ namespace cmonitor.plugins.tunnel
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Debug($"tunnel connect from {tunnelTransportInfo.Local.MachineName}->{tunnelTransportInfo.ToJson()}");
Logger.Instance.Debug($"tunnel connect from {tunnelTransportInfo.Remote.MachineName}->{tunnelTransportInfo.ToJson()}");
}
CheckDic(tunnelTransportInfo.Local.MachineName, out TunnelConnectInfo info);
CheckDic(tunnelTransportInfo.Remote.MachineName, out TunnelConnectInfo info);
info.Status = TunnelConnectStatus.Connecting;
Interlocked.Exchange(ref connectionsChangeFlag, 1);
}

View File

@@ -1,4 +1,6 @@
using cmonitor.plugins.tunnel.server;
using cmonitor.plugins.tunnel.messenger;
using cmonitor.plugins.tunnel.server;
using cmonitor.server;
using common.libs.extends;
using MemoryPack;
using System.Net;
@@ -8,7 +10,16 @@ namespace cmonitor.plugins.tunnel.compact
{
public sealed class CompactSelfHost : ICompact
{
public string Type => "self";
public string Name => "self";
private readonly TcpServer tcpServer;
private readonly MessengerSender messengerSender;
public CompactSelfHost(TcpServer tcpServer, MessengerSender messengerSender)
{
this.tcpServer = tcpServer;
this.messengerSender = messengerSender;
}
public async Task<TunnelCompactIPEndPoint> GetTcpExternalIPAsync(IPEndPoint server)
{
@@ -17,23 +28,22 @@ namespace cmonitor.plugins.tunnel.compact
socket.IPv6Only(server.AddressFamily, false);
await socket.ConnectAsync(server).WaitAsync(TimeSpan.FromSeconds(5));
byte[] bytes = new byte[128];
int length = await socket.ReceiveAsync(bytes.AsMemory(), SocketFlags.None);
if (length == 0)
{
return null;
}
IConnection connection = tcpServer.BindReceive(socket);
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap { Connection = connection, MessengerId = (ushort)TunnelMessengerIds.ExternalIP });
if (resp.Code != MessageResponeCodes.OK) return null;
IPEndPoint local = socket.LocalEndPoint as IPEndPoint;
socket.SafeClose();
TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(bytes.AsSpan(0,length));
connection.Disponse();
TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(resp.Data.Span);
return new TunnelCompactIPEndPoint { Local = local, Remote = tunnelExternalIPInfo.ExternalIP };
}
public async Task<TunnelCompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server)
{
return null;
/*
using UdpClient udpClient = new UdpClient();
udpClient.Client.Reuse(true);
await udpClient.SendAsync(new byte[1] { 0 }, server);
@@ -46,6 +56,7 @@ namespace cmonitor.plugins.tunnel.compact
TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(result.Buffer);
return new TunnelCompactIPEndPoint { Local = udpClient.Client.LocalEndPoint as IPEndPoint, Remote = tunnelExternalIPInfo.ExternalIP };
*/
}
}
}

View File

@@ -23,9 +23,9 @@ namespace cmonitor.plugins.tunnel.compact
{
IEnumerable<Type> types = ReflectionHelper.GetInterfaceSchieves(assembs, typeof(ICompact));
types = config.Data.Common.PluginContains(types);
compacts = types.Select(c => (ICompact)serviceProvider.GetService(c)).Where(c => c != null).Where(c => string.IsNullOrWhiteSpace(c.Type) == false).ToList();
compacts = types.Select(c => (ICompact)serviceProvider.GetService(c)).Where(c => c != null).Where(c => string.IsNullOrWhiteSpace(c.Name) == false).ToList();
Logger.Instance.Warning($"load tunnel compacts:{string.Join(",", compacts.Select(c => c.Type))}");
Logger.Instance.Warning($"load tunnel compacts:{string.Join(",", compacts.Select(c => c.Name))}");
}
public async Task<TunnelCompactIPEndPoint[]> GetExternalIPAsync(ProtocolType protocolType)
@@ -36,7 +36,7 @@ namespace cmonitor.plugins.tunnel.compact
{
TunnelCompactInfo item = config.Data.Client.Tunnel.Servers[i];
if (item.Disabled) continue;
ICompact compact = compacts.FirstOrDefault(c => c.Type == item.Type);
ICompact compact = compacts.FirstOrDefault(c => c.Name == item.Name);
if (compact == null) continue;
try

View File

@@ -4,7 +4,7 @@ namespace cmonitor.plugins.tunnel.compact
{
public interface ICompact
{
public string Type { get; }
public string Name { get; }
public Task<TunnelCompactIPEndPoint> GetTcpExternalIPAsync(IPEndPoint server);
public Task<TunnelCompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server);
}

View File

@@ -13,10 +13,7 @@ namespace cmonitor.config
public sealed class TunnelConfigClientInfo
{
public TunnelCompactInfo[] Servers { get; set; } = new TunnelCompactInfo[]
{
new TunnelCompactInfo { Type="self", Host="127.0.0.1:1804" }
};
public TunnelCompactInfo[] Servers { get; set; } = Array.Empty<TunnelCompactInfo>();
[JsonIgnore]
public int RouteLevel { get; set; }
@@ -24,12 +21,11 @@ namespace cmonitor.config
public sealed class TunnelConfigServerInfo
{
public int ListenPort { get; set; } = 1804;
}
public sealed class TunnelCompactInfo
{
public string Type { get; set; }
public string Name { get; set; }
public string Host { get; set; }
public bool Disabled { get; set; }
}

View File

@@ -2,7 +2,9 @@
using cmonitor.plugins.tunnel.transport;
using cmonitor.server;
using common.libs;
using common.libs.extends;
using MemoryPack;
using System.Net;
namespace cmonitor.plugins.tunnel.messenger
{
@@ -50,7 +52,6 @@ namespace cmonitor.plugins.tunnel.messenger
}
}
public sealed class TunnelServerMessenger : IMessenger
{
private readonly MessengerSender messengerSender;
@@ -90,7 +91,7 @@ namespace cmonitor.plugins.tunnel.messenger
MessengerId = (ushort)TunnelMessengerIds.Info,
Payload = connection.ReceiveRequestWrap.Payload
});
if (resp.Code == MessageResponeCodes.OK)
if (resp.Code == MessageResponeCodes.OK && resp.Data.Span.Length > 0)
{
connection.Write(MemoryPackSerializer.Serialize(MemoryPackSerializer.Deserialize<TunnelTransportExternalIPInfo>(resp.Data.Span)));
}
@@ -111,5 +112,18 @@ namespace cmonitor.plugins.tunnel.messenger
});
}
}
[MessengerId((ushort)TunnelMessengerIds.ExternalIP)]
public void ExternalIP(IConnection connection)
{
connection.Write(MemoryPackSerializer.Serialize(new TunnelExternalIPInfo { ExternalIP = connection.Address }));
}
}
[MemoryPackable]
public sealed partial class TunnelExternalIPInfo
{
[MemoryPackAllowSerialize]
public IPEndPoint ExternalIP { get; set; }
}
}

View File

@@ -11,6 +11,9 @@
Fail = 2005,
FailForward = 2006,
ExternalIP = 2007,
None = 2099
}
}

View File

@@ -1,161 +0,0 @@
using common.libs;
using common.libs.extends;
using MemoryPack;
using System.Net;
using System.Net.Sockets;
namespace cmonitor.plugins.tunnel.server
{
public sealed class TunnelExternalIPServer
{
private SocketAsyncEventArgs acceptEventArg;
private Socket socket;
private UdpClient socketUdp;
public void Start(int port)
{
try
{
Stop();
IPEndPoint localEndPoint = new IPEndPoint(NetworkHelper.IPv6Support ? IPAddress.IPv6Any : IPAddress.Any, port);
socket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.IPv6Only(localEndPoint.AddressFamily, false);
socket.ReuseBind(localEndPoint);
socket.Listen(int.MaxValue);
acceptEventArg = new SocketAsyncEventArgs
{
UserToken = new AsyncUserToken
{
SourceSocket = socket
},
SocketFlags = SocketFlags.None,
};
acceptEventArg.Completed += IO_Completed;
StartAccept(acceptEventArg);
socketUdp = new UdpClient(new IPEndPoint(IPAddress.Any, port));
socketUdp.Client.EnableBroadcast = true;
socketUdp.Client.WindowsUdpBug();
IAsyncResult result = socketUdp.BeginReceive(ReceiveCallbackUdp, null);
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
}
}
private void StartAccept(SocketAsyncEventArgs acceptEventArg)
{
acceptEventArg.AcceptSocket = null;
AsyncUserToken token = (AsyncUserToken)acceptEventArg.UserToken;
try
{
if (token.SourceSocket.AcceptAsync(acceptEventArg) == false)
{
ProcessAccept(acceptEventArg);
}
}
catch (Exception)
{
token.Clear();
}
}
private void IO_Completed(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Accept:
ProcessAccept(e);
break;
default:
break;
}
}
private void ProcessAccept(SocketAsyncEventArgs e)
{
if (e.AcceptSocket != null)
{
SocketAsyncEventArgs receiveEventArg = new SocketAsyncEventArgs
{
UserToken = new AsyncUserToken
{
SourceSocket = e.AcceptSocket
},
SocketFlags = SocketFlags.None,
};
WriteExternalIP(receiveEventArg);
StartAccept(e);
}
}
private async void WriteExternalIP(SocketAsyncEventArgs e)
{
AsyncUserToken token = e.UserToken as AsyncUserToken;
if (token.SourceSocket != null)
{
IPEndPoint ep = token.SourceSocket.RemoteEndPoint as IPEndPoint;
Memory<byte> memory = MemoryPackSerializer.Serialize(new TunnelExternalIPInfo { ExternalIP = ep });
await token.SourceSocket.SendAsync(memory);
}
}
private async void ReceiveCallbackUdp(IAsyncResult result)
{
try
{
IPEndPoint ep = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
byte[] _ = socketUdp.EndReceive(result, ref ep);
Memory<byte> memory = MemoryPackSerializer.Serialize(new TunnelExternalIPInfo { ExternalIP = ep });
await socketUdp.SendAsync(memory, ep);
result = socketUdp.BeginReceive(ReceiveCallbackUdp, null);
}
catch (Exception)
{
}
}
private void CloseClientSocket(SocketAsyncEventArgs e)
{
if (e == null) return;
AsyncUserToken token = e.UserToken as AsyncUserToken;
if (token.SourceSocket != null)
{
token.Clear();
e.Dispose();
}
}
public void Stop()
{
CloseClientSocket(acceptEventArg);
socketUdp?.Close();
}
}
public sealed class AsyncUserToken
{
public Socket SourceSocket { get; set; }
public void Clear()
{
SourceSocket?.SafeClose();
SourceSocket = null;
GC.Collect();
}
}
[MemoryPackable]
public sealed partial class TunnelExternalIPInfo
{
[MemoryPackAllowSerialize]
public IPEndPoint ExternalIP { get; set; }
}
}

View File

@@ -13,7 +13,7 @@ namespace cmonitor.plugins.tunnel.transport
/// <summary>
/// 发送连接信息
/// </summary>
public Func<TunnelTransportInfo, Task> OnSendConnectBegin { get; set; }
public Func<TunnelTransportInfo, Task<bool>> OnSendConnectBegin { get; set; }
public Func<TunnelTransportInfo, Task> OnSendConnectFail { get; set; }
/// <summary>
/// 收到连接信息

View File

@@ -12,7 +12,7 @@ namespace cmonitor.plugins.tunnel.transport
public string Name => "TcpNutssb";
public ProtocolType Type => ProtocolType.Tcp;
public Func<TunnelTransportInfo, Task> OnSendConnectBegin { get; set; } = async (info) => { await Task.CompletedTask; };
public Func<TunnelTransportInfo, Task<bool>> OnSendConnectBegin { get; set; } = async (info) => { return await Task.FromResult<bool>(false); };
public Func<TunnelTransportInfo, Task> OnSendConnectFail { get; set; } = async (info) => { await Task.CompletedTask; };
public Action<TunnelTransportInfo> OnConnectBegin { get; set; } = (info) => { };
public Action<TunnelTransportInfo> OnConnecting { get; set; }
@@ -22,7 +22,6 @@ namespace cmonitor.plugins.tunnel.transport
private readonly TunnelBindServer tunnelBindServer;
public TransportTcpNutssb(TunnelBindServer tunnelBindServer)
{
this.tunnelBindServer = tunnelBindServer;
@@ -34,26 +33,30 @@ namespace cmonitor.plugins.tunnel.transport
{
OnConnecting(tunnelTransportInfo);
//正向连接
tunnelTransportInfo.Direction = TunnelTransportDirection.Forward;
await OnSendConnectBegin(tunnelTransportInfo);
TunnelTransportState state = await ConnectForward(tunnelTransportInfo);
if (state != null)
if (await OnSendConnectBegin(tunnelTransportInfo) == false)
{
return state;
OnConnectFail(tunnelTransportInfo.Remote.MachineName);
return null;
}
TunnelTransportState state = await ConnectForward(tunnelTransportInfo);
if (state != null) return state;
//反向连接
TunnelTransportInfo tunnelTransportInfo1 = tunnelTransportInfo.ToJsonFormat().DeJson<TunnelTransportInfo>();
tunnelTransportInfo1.Direction = TunnelTransportDirection.Reverse;
tunnelBindServer.Bind(tunnelTransportInfo1.Local.Local, tunnelTransportInfo1);
BindAndTTL(tunnelTransportInfo1);
await OnSendConnectBegin(tunnelTransportInfo1);
state = await WaitReverse(tunnelTransportInfo1);
if (state != null)
if (await OnSendConnectBegin(tunnelTransportInfo1) == false)
{
return state;
OnConnectFail(tunnelTransportInfo.Remote.MachineName);
return null;
}
state = await WaitReverse(tunnelTransportInfo1);
if (state != null) return state;
//正向反向都失败
await OnSendConnectFail(tunnelTransportInfo);
OnConnectFail(tunnelTransportInfo.Remote.MachineName);
return null;
@@ -109,10 +112,10 @@ namespace cmonitor.plugins.tunnel.transport
Socket targetSocket = new(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
targetSocket.IPv6Only(ep.Address.AddressFamily, false);
targetSocket.ReuseBind(new IPEndPoint(ep.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, tunnelTransportInfo.Local.Local.Port));
IAsyncResult result = targetSocket.BeginConnect(ep, null, null);
for (int i = 0; i < 25; i++)
int times = ep.Address.Equals(tunnelTransportInfo.Remote.Remote.Address) ? 25 : 5;
for (int i = 0; i < times; i++)
{
if (result.IsCompleted)
{
@@ -120,6 +123,7 @@ namespace cmonitor.plugins.tunnel.transport
}
await Task.Delay(20);
}
try
{
if (result.IsCompleted == false)
@@ -190,12 +194,20 @@ namespace cmonitor.plugins.tunnel.transport
TaskCompletionSource<TunnelTransportState> tcs = new TaskCompletionSource<TunnelTransportState>();
reverseDic.TryAdd(tunnelTransportInfo.Remote.MachineName, tcs);
TunnelTransportState state = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(3));
reverseDic.TryRemove(tunnelTransportInfo.Remote.MachineName, out _);
try
{
TunnelTransportState state = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(3000));
return state;
}
catch (Exception)
{
}
finally
{
reverseDic.TryRemove(tunnelTransportInfo.Remote.MachineName, out _);
}
return null;
}
private void OnTcpConnected(object state, Socket socket)

View File

@@ -21,6 +21,9 @@ namespace cmonitor.server
public IPEndPoint Address { get; }
public IPEndPoint LocalAddress { get; }
public Socket TcpSourceSocket { get; }
public Socket TcpTargetSocket { get; set; }
#region
/// <summary>
/// 请求数据包装对象
@@ -41,14 +44,14 @@ namespace cmonitor.server
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public Task<bool> Send(ReadOnlyMemory<byte> data, bool unconnectedMessage = false);
public Task<bool> Send(ReadOnlyMemory<byte> data);
/// <summary>
/// 发送
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
public Task<bool> Send(byte[] data, int length, bool unconnectedMessage = false);
public Task<bool> Send(byte[] data, int length);
/// <summary>
/// 销毁
@@ -97,6 +100,9 @@ namespace cmonitor.server
public IPEndPoint Address { get; protected set; }
public IPEndPoint LocalAddress { get; protected set; }
public Socket TcpSourceSocket { get; protected set; }
public Socket TcpTargetSocket { get; set; }
public bool Relayed { get; set; }
#region
/// <summary>
@@ -194,14 +200,14 @@ namespace cmonitor.server
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public abstract Task<bool> Send(ReadOnlyMemory<byte> data, bool logger = false);
public abstract Task<bool> Send(ReadOnlyMemory<byte> data);
/// <summary>
/// 发送
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
public abstract Task<bool> Send(byte[] data, int length, bool logger = false);
public abstract Task<bool> Send(byte[] data, int length);
/// <summary>
/// 销毁
@@ -218,16 +224,16 @@ namespace cmonitor.server
{
public TcpConnection(Socket tcpSocket) : base()
{
TcpSocket = tcpSocket;
TcpSourceSocket = tcpSocket;
IPEndPoint address = TcpSocket.RemoteEndPoint as IPEndPoint ?? new IPEndPoint(IPAddress.Any, 0);
IPEndPoint address = TcpSourceSocket.RemoteEndPoint as IPEndPoint ?? new IPEndPoint(IPAddress.Any, 0);
if (address.Address.AddressFamily == AddressFamily.InterNetworkV6 && address.Address.IsIPv4MappedToIPv6)
{
address = new IPEndPoint(new IPAddress(address.Address.GetAddressBytes()[^4..]), address.Port);
}
Address = address;
IPEndPoint localaddress = TcpSocket.LocalEndPoint as IPEndPoint ?? new IPEndPoint(IPAddress.Any, 0);
IPEndPoint localaddress = TcpSourceSocket.LocalEndPoint as IPEndPoint ?? new IPEndPoint(IPAddress.Any, 0);
if (localaddress.Address.AddressFamily == AddressFamily.InterNetworkV6 && localaddress.Address.IsIPv4MappedToIPv6)
{
localaddress = new IPEndPoint(new IPAddress(localaddress.Address.GetAddressBytes()[^4..]), localaddress.Port);
@@ -238,24 +244,20 @@ namespace cmonitor.server
/// <summary>
/// 已连接
/// </summary>
public override bool Connected => TcpSocket != null && TcpSocket.Connected;
public override bool Connected => TcpSourceSocket != null && TcpSourceSocket.Connected;
/// <summary>
/// socket
/// </summary>
public Socket TcpSocket { get; private set; }
/// <summary>
/// 发送
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public override async Task<bool> Send(ReadOnlyMemory<byte> data, bool unconnectedMessage = false)
public override async Task<bool> Send(ReadOnlyMemory<byte> data)
{
if (Connected)
{
try
{
await TcpSocket.SendAsync(data, SocketFlags.None);
await TcpSourceSocket.SendAsync(data, SocketFlags.None);
//SentBytes += (ulong)data.Length;
return true;
}
@@ -274,9 +276,9 @@ namespace cmonitor.server
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
public override async Task<bool> Send(byte[] data, int length, bool unconnectedMessage = false)
public override async Task<bool> Send(byte[] data, int length)
{
return await Send(data.AsMemory(0, length), unconnectedMessage);
return await Send(data.AsMemory(0, length));
}
/// <summary>
/// 销毁
@@ -284,10 +286,13 @@ namespace cmonitor.server
public override void Disponse()
{
base.Disponse();
if (TcpSocket != null)
if (TcpSourceSocket != null)
{
TcpSocket.SafeClose();
TcpSocket.Dispose();
TcpSourceSocket.SafeClose();
TcpSourceSocket.Dispose();
TcpTargetSocket?.SafeClose();
TcpTargetSocket?.Dispose();
}
}
}

View File

@@ -1,8 +1,10 @@
using cmonitor.config;
using common.libs;
using common.libs.extends;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace cmonitor.server
{
@@ -12,6 +14,8 @@ namespace cmonitor.server
private Socket socket;
private UdpClient socketUdp;
private CancellationTokenSource cancellationTokenSource;
private Memory<byte> relayFLagData = Encoding.UTF8.GetBytes("snltty.relay");
public Func<IConnection, Task> OnPacket { get; set; } = async (connection) => { await Task.CompletedTask; };
public Action<int> OnDisconnected { get; set; }
@@ -148,17 +152,17 @@ namespace cmonitor.server
Connection = CreateConnection(socket)
};
SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs
SocketAsyncEventArgs saea = new SocketAsyncEventArgs
{
UserToken = userToken,
SocketFlags = SocketFlags.None,
};
userToken.PoolBuffer = new byte[bufferSize];
readEventArgs.SetBuffer(userToken.PoolBuffer, 0, bufferSize);
readEventArgs.Completed += IO_Completed;
if (socket.ReceiveAsync(readEventArgs) == false)
saea.SetBuffer(userToken.PoolBuffer, 0, bufferSize);
saea.Completed += IO_Completed;
if (socket.ReceiveAsync(saea) == false)
{
ProcessReceive(readEventArgs);
ProcessReceive(saea);
}
return userToken.Connection;
}
@@ -179,7 +183,9 @@ namespace cmonitor.server
{
int offset = e.Offset;
int length = e.BytesTransferred;
await ReadPacket(token, e.Buffer, offset, length);
bool res = await ReadPacket(token, e.Buffer, offset, length);
if (res == false) return;
if (token.Socket.Available > 0)
{
@@ -188,7 +194,8 @@ namespace cmonitor.server
length = token.Socket.Receive(e.Buffer);
if (length > 0)
{
await ReadPacket(token, e.Buffer, 0, length);
res = await ReadPacket(token, e.Buffer, 0, length);
if (res == false) return;
}
else
{
@@ -203,7 +210,6 @@ namespace cmonitor.server
CloseClientSocket(e);
return;
}
if (token.Socket.ReceiveAsync(e) == false)
{
ProcessReceive(e);
@@ -222,7 +228,23 @@ namespace cmonitor.server
CloseClientSocket(e);
}
}
private async Task ReadPacket(AsyncUserToken token, byte[] data, int offset, int length)
private async Task<bool> ReadPacket(AsyncUserToken token, byte[] data, int offset, int length)
{
if (token.Connection.TcpTargetSocket != null)
{
if (token.DataBuffer.Size > 0)
{
await token.Connection.TcpTargetSocket.SendAsync(token.DataBuffer.Data.Slice(0, token.DataBuffer.Size), SocketFlags.None);
token.DataBuffer.Clear();
}
await token.Connection.TcpTargetSocket.SendAsync(data.AsMemory(offset, length), SocketFlags.None);
return true;
}
else if (length == relayFLagData.Length && data.AsSpan(offset, length).SequenceEqual(relayFLagData.Span))
{
return false;
}
else
{
//是一个完整的包
if (token.DataBuffer.Size == 0 && length > 4)
@@ -233,7 +255,7 @@ namespace cmonitor.server
{
token.Connection.ReceiveData = data.AsMemory(offset, packageLen + 4);
await OnPacket(token.Connection);
return;
return true;
}
}
@@ -252,6 +274,8 @@ namespace cmonitor.server
token.DataBuffer.RemoveRange(0, packageLen + 4);
} while (token.DataBuffer.Size > 4);
}
return true;
}
private void CloseClientSocket(SocketAsyncEventArgs e)
{
@@ -294,11 +318,14 @@ namespace cmonitor.server
public Socket Socket { get; set; }
public ReceiveDataBuffer DataBuffer { get; set; } = new ReceiveDataBuffer();
public byte[] PoolBuffer { get; set; }
public void Clear()
{
Socket?.SafeClose();
Connection?.Disponse();
Socket = null;
PoolBuffer = Helper.EmptyArray;
DataBuffer.Clear(true);

View File

@@ -7,6 +7,11 @@ call npm install
call npm run build
cd ../
cd cmonitor.web.client
call npm install
call npm run build
cd ../
dotnet publish ./cmonitor.sas.service -c release -f net8.0 -o public/extends/ -r win-x64 -p:PublishTrimmed=true -p:TrimMode=partial --self-contained true -p:TieredPGO=true -p:DebugType=none -p:DebugSymbols=false -p:PublishSingleFile=true -p:EnableCompressionInSingleFile=true -p:DebuggerSupport=false -p:EnableUnsafeBinaryFormatterSerialization=false -p:EnableUnsafeUTF7Encoding=false -p:HttpActivityPropagationSupport=false -p:InvariantGlobalization=true -p:MetadataUpdaterSupport=false -p:UseSystemResourceKeys=true
dotnet publish ./cmonitor.install.win -c release -f net8.0-windows -r win-x64 -o public/extends/ -p:PublishSingleFile=true --self-contained false
dotnet publish ./cmonitor.snatch.win -c release -f net8.0-windows -r win-x64 -o public/extends/ -p:PublishSingleFile=true --self-contained false

View File

@@ -20,6 +20,7 @@ for %%r in (win-x64,win-x64-any) do (
for %%r in (linux-x64,linux-x64-any) do (
echo F|xcopy "public\\extends\\web\\*" "public\\publish\\%%r\\web\\*" /s /f /h /y
echo F|xcopy "public\\extends\\web-client\\*" "public\\publish\\%%r\\web-client\\*" /s /f /h /y
echo F|del "public\\publish\\%%r\\plugins"
rd /s /q "public\\publish\\%%r\\plugins"
)