mirror of
				https://github.com/snltty/linker.git
				synced 2025-10-31 12:36:48 +08:00 
			
		
		
		
	增加打洞和中继插件,后续桌面共享的代理将有这两个插件去实现通信
This commit is contained in:
		
							
								
								
									
										5
									
								
								cmonitor.web.client/src/apis/relay.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								cmonitor.web.client/src/apis/relay.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| import { sendWebsocketMsg } from './request' | ||||
|  | ||||
| export const updateRelayConnect = (machineName) => { | ||||
|     return sendWebsocketMsg('relay/Connect', machineName); | ||||
| } | ||||
							
								
								
									
										21
									
								
								cmonitor.web.client/src/apis/signin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								cmonitor.web.client/src/apis/signin.js
									
									
									
									
									
										Normal 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); | ||||
| } | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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'; | ||||
|   | ||||
| @@ -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'); | ||||
|   | ||||
| @@ -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 | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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(); | ||||
|                 } | ||||
|             } | ||||
|   | ||||
							
								
								
									
										77
									
								
								cmonitor/plugins/relay/RelayApiController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								cmonitor/plugins/relay/RelayApiController.cs
									
									
									
									
									
										Normal 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; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										45
									
								
								cmonitor/plugins/relay/RelayStartup.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								cmonitor/plugins/relay/RelayStartup.cs
									
									
									
									
									
										Normal 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) | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										90
									
								
								cmonitor/plugins/relay/RelayTransfer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								cmonitor/plugins/relay/RelayTransfer.cs
									
									
									
									
									
										Normal 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; | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								cmonitor/plugins/relay/config/Config.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								cmonitor/plugins/relay/config/Config.cs
									
									
									
									
									
										Normal 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; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										112
									
								
								cmonitor/plugins/relay/messenger/RelayMessenger.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								cmonitor/plugins/relay/messenger/RelayMessenger.cs
									
									
									
									
									
										Normal 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; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
							
								
								
									
										12
									
								
								cmonitor/plugins/relay/messenger/RelayMessengerIds.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								cmonitor/plugins/relay/messenger/RelayMessengerIds.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| namespace cmonitor.plugins.relay.messenger | ||||
| { | ||||
|     public enum RelayMessengerIds : ushort | ||||
|     { | ||||
|         Update = 2100, | ||||
|  | ||||
|         Relay = 2101, | ||||
|         RelayForward = 2102, | ||||
|  | ||||
|         None = 2199 | ||||
|     } | ||||
| } | ||||
							
								
								
									
										38
									
								
								cmonitor/plugins/relay/transport/ITransport.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								cmonitor/plugins/relay/transport/ITransport.cs
									
									
									
									
									
										Normal 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; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										73
									
								
								cmonitor/plugins/relay/transport/TransportSelfHost.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								cmonitor/plugins/relay/transport/TransportSelfHost.cs
									
									
									
									
									
										Normal 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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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; } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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 () => | ||||
|             { | ||||
| @@ -110,7 +53,7 @@ namespace cmonitor.plugins.tunnel | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
|                 { | ||||
|                     Console.WriteLine(ex+""); | ||||
|                     Console.WriteLine(ex + ""); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
| @@ -120,7 +63,7 @@ namespace cmonitor.plugins.tunnel | ||||
|             { | ||||
|                 if (state.TransactionId == "test" && state.TransportType == ProtocolType.Tcp) | ||||
|                 { | ||||
|                     tunnelBindServer.BindReceive(state.ConnectedObject as Socket, null, async (token,data) => | ||||
|                     tunnelBindServer.BindReceive(state.ConnectedObject as Socket, null, async (token, data) => | ||||
|                     { | ||||
|                         Logger.Instance.Debug($"tunnel [{state.TransactionId}] receive {BitConverter.ToInt32(data.Span)}"); | ||||
|                     }); | ||||
| @@ -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; } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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}"); | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|         } | ||||
|   | ||||
| @@ -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 }; | ||||
|             */ | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
|   | ||||
| @@ -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; } | ||||
|     } | ||||
|   | ||||
| @@ -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; } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,9 @@ | ||||
|         Fail = 2005, | ||||
|         FailForward = 2006, | ||||
|  | ||||
|  | ||||
|         ExternalIP = 2007, | ||||
|  | ||||
|         None = 2099 | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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; } | ||||
|     } | ||||
| } | ||||
| @@ -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> | ||||
|         /// 收到连接信息 | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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" | ||||
| ) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 snltty
					snltty