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' | 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) => { | export const updateTunnelConnect = (machineName) => { | ||||||
|     return sendWebsocketMsg('tunnel/TunnelConnect', machineName); |     return sendWebsocketMsg('tunnel/Connect', machineName); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ | |||||||
| <script> | <script> | ||||||
| import { computed, onMounted, reactive, watch } from 'vue'; | import { computed, onMounted, reactive, watch } from 'vue'; | ||||||
| import { initWebsocket, subWebsocketState } from '../apis/request' | import { initWebsocket, subWebsocketState } from '../apis/request' | ||||||
| import { getConfig,getSignInfo } from '../apis/tunnel' | import { getConfig,getSignInfo } from '../apis/signin' | ||||||
| import { useRoute } from 'vue-router'; | import { useRoute } from 'vue-router'; | ||||||
| import { injectGlobalData } from '../provide'; | import { injectGlobalData } from '../provide'; | ||||||
| export default { | export default { | ||||||
| @@ -65,12 +65,14 @@ export default { | |||||||
|  |  | ||||||
|         const _getConfig = ()=>{ |         const _getConfig = ()=>{ | ||||||
|             getConfig().then((res)=>{ |             getConfig().then((res)=>{ | ||||||
|  |                 console.log(res); | ||||||
|                 globalData.value.config.Common = res.Data.Common; |                 globalData.value.config.Common = res.Data.Common; | ||||||
|                 globalData.value.config.Client = res.Data.Client; |                 globalData.value.config.Client = res.Data.Client; | ||||||
|                 setTimeout(()=>{ |                 setTimeout(()=>{ | ||||||
|                     _getConfig(); |                     _getConfig(); | ||||||
|                 },1000); |                 },1000); | ||||||
|             }).catch((err)=>{ |             }).catch((err)=>{ | ||||||
|  |                 console.log(err); | ||||||
|                 setTimeout(()=>{ |                 setTimeout(()=>{ | ||||||
|                     _getConfig(); |                     _getConfig(); | ||||||
|                 },1000); |                 },1000); | ||||||
|   | |||||||
| @@ -75,7 +75,7 @@ | |||||||
|     </el-dialog> |     </el-dialog> | ||||||
| </template> | </template> | ||||||
| <script> | <script> | ||||||
| import { updateConfigSet, updateConfigSetServers } from '@/apis/tunnel'; | import { updateConfigSet, updateConfigSetServers } from '@/apis/signin'; | ||||||
| import { injectGlobalData } from '@/provide'; | import { injectGlobalData } from '@/provide'; | ||||||
| import { ElMessage } from 'element-plus'; | import { ElMessage } from 'element-plus'; | ||||||
| import { computed, reactive } from 'vue'; | 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 'element-plus/theme-chalk/dark/css-vars.css' | ||||||
|  |  | ||||||
| import { | import { | ||||||
|     ChromeFilled, |     ArrowDown, | ||||||
| } from '@element-plus/icons-vue' | } from '@element-plus/icons-vue' | ||||||
| app.component(ChromeFilled.name, ChromeFilled); | app.component(ArrowDown.name, ArrowDown); | ||||||
|  |  | ||||||
|  |  | ||||||
| app.use(ElementPlus, { size: 'default' }).use(router).mount('#app'); | app.use(ElementPlus, { size: 'default' }).use(router).mount('#app'); | ||||||
|   | |||||||
| @@ -18,8 +18,18 @@ | |||||||
|             <el-table-column prop="LastSignIn" label="最后登入" width="140" /> |             <el-table-column prop="LastSignIn" label="最后登入" width="140" /> | ||||||
|             <el-table-column label="操作"> |             <el-table-column label="操作"> | ||||||
|                 <template #default="scope"> |                 <template #default="scope"> | ||||||
|                     <el-button size="small" @click="handleTestTunnel(scope.row.MachineName)">测试</el-button> |                     <el-dropdown> | ||||||
|                     <el-popconfirm confirm-button-text="确认" cancel-button-text="取消" title="删除不可逆,是否确认?" @confirm="handleDelTunnel(scope.row.MachineName)"> |                         <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> |                         <template #reference> | ||||||
|                             <el-button type="danger" size="small">删除</el-button> |                             <el-button type="danger" size="small">删除</el-button> | ||||||
|                         </template> |                         </template> | ||||||
| @@ -37,7 +47,9 @@ | |||||||
|     </div> |     </div> | ||||||
| </template> | </template> | ||||||
| <script> | <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 {subWebsocketState} from '@/apis/request.js' | ||||||
| import {injectGlobalData} from '../provide.js' | import {injectGlobalData} from '../provide.js' | ||||||
| import {reactive,onMounted, ref, nextTick, onUnmounted} from 'vue' | import {reactive,onMounted, ref, nextTick, onUnmounted} from 'vue' | ||||||
| @@ -73,7 +85,10 @@ export default { | |||||||
|         const handleTestTunnel = (name)=>{ |         const handleTestTunnel = (name)=>{ | ||||||
|             updateTunnelConnect(name); |             updateTunnelConnect(name); | ||||||
|         } |         } | ||||||
|         const handleDelTunnel = (name)=>{ |         const handleTestRelay = (name)=>{ | ||||||
|  |             updateRelayConnect(name); | ||||||
|  |         } | ||||||
|  |         const handleDel = (name)=>{ | ||||||
|             updateSignInDel(name).then(()=>{ |             updateSignInDel(name).then(()=>{ | ||||||
|                 _getSignList(); |                 _getSignList(); | ||||||
|             }); |             }); | ||||||
| @@ -89,7 +104,7 @@ export default { | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         return { |         return { | ||||||
|             state,wrap,handlePageChange,handleTestTunnel,handleDelTunnel |             state,wrap,handlePageChange,handleTestTunnel,handleTestRelay,handleDel | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,11 +1,11 @@ | |||||||
| import { sendWebsocketMsg } from './request' | import { sendWebsocketMsg } from './request' | ||||||
|  |  | ||||||
| export const getList = (groupid) => { | export const getList = (groupid) => { | ||||||
|     return sendWebsocketMsg('signin/list', groupid); |     return sendWebsocketMsg('signinserver/list', groupid); | ||||||
| } | } | ||||||
| export const getConfig = () => { | export const getConfig = () => { | ||||||
|     return sendWebsocketMsg('signin/config'); |     return sendWebsocketMsg('signinserver/config'); | ||||||
| } | } | ||||||
| export const delDevice = (name) => { | 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.client.","cmonitor.server.","cmonitor.serializes.", | ||||||
|                         "cmonitor.plugins.signin.", "cmonitor.plugins.watch.","cmonitor.plugins.devices.","cmonitor.plugins.report.", |                         "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(); |                     }).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.config; | ||||||
| using cmonitor.plugins.signin.messenger; | using cmonitor.plugins.signin.messenger; | ||||||
| using common.libs.api; | using common.libs.api; | ||||||
|  | using cmonitor.client.api; | ||||||
|  | using common.libs.extends; | ||||||
|  | using cmonitor.client; | ||||||
|  | using cmonitor.server; | ||||||
|  | using MemoryPack; | ||||||
|  |  | ||||||
| namespace cmonitor.plugins.signin | namespace cmonitor.plugins.signin | ||||||
| { | { | ||||||
|     public sealed class SignInApiController : IApiServerController |     public sealed class SignInServerApiController : IApiServerController | ||||||
|     { |     { | ||||||
|         private readonly SignCaching signCaching; |         private readonly SignCaching signCaching; | ||||||
|         private readonly Config config; |         private readonly Config config; | ||||||
|         public SignInApiController(SignCaching signCaching, Config config) |         public SignInServerApiController(SignCaching signCaching, Config config) | ||||||
|         { |         { | ||||||
|             this.signCaching = signCaching; |             this.signCaching = signCaching; | ||||||
|             this.config = config; |             this.config = config; | ||||||
| @@ -31,4 +36,77 @@ namespace cmonitor.plugins.signin | |||||||
|             return config; |             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) |         public void AddClient(ServiceCollection serviceCollection, Config config, Assembly[] assemblies) | ||||||
|         { |         { | ||||||
|  |             serviceCollection.AddSingleton<SignInClientApiController>(); | ||||||
|  |              | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies) |         public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies) | ||||||
|         { |         { | ||||||
|             serviceCollection.AddSingleton<SignCaching>(); |             serviceCollection.AddSingleton<SignCaching>(); | ||||||
|             serviceCollection.AddSingleton<SignInMessenger>(); |             serviceCollection.AddSingleton<SignInMessenger>(); | ||||||
|             serviceCollection.AddSingleton<SignInApiController>(); |             serviceCollection.AddSingleton<SignInServerApiController>(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies) |         public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies) | ||||||
|   | |||||||
| @@ -16,80 +16,23 @@ namespace cmonitor.plugins.tunnel | |||||||
| { | { | ||||||
|     public sealed class TunnelApiController : IApiClientController |     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 TunnelTransfer tunnelTransfer; | ||||||
|         private readonly TunnelBindServer tunnelBindServer; |         private readonly TunnelBindServer tunnelBindServer; | ||||||
|  |  | ||||||
|         public TunnelApiController(Config config, ClientSignInState clientSignInState, ClientSignInTransfer clientSignInTransfer, MessengerSender messengerSender, TunnelTransfer tunnelTransfer, |         public TunnelApiController(TunnelTransfer tunnelTransfer, | ||||||
|             TunnelBindServer tunnelBindServer) |             TunnelBindServer tunnelBindServer) | ||||||
|         { |         { | ||||||
|             this.config = config; |  | ||||||
|             this.clientSignInState = clientSignInState; |  | ||||||
|             this.clientSignInTransfer = clientSignInTransfer; |  | ||||||
|             this.messengerSender = messengerSender; |  | ||||||
|             this.tunnelTransfer = tunnelTransfer; |             this.tunnelTransfer = tunnelTransfer; | ||||||
|             this.tunnelBindServer = tunnelBindServer; |             this.tunnelBindServer = tunnelBindServer; | ||||||
|  |  | ||||||
|             TunnelTest(); |             TunnelTest(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public Config Config(ApiControllerParamsInfo param) |         public Dictionary<string, TunnelConnectInfo> Connections(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) |  | ||||||
|         { |         { | ||||||
|             return tunnelTransfer.Connections; |             return tunnelTransfer.Connections; | ||||||
|         } |         } | ||||||
|         public void TunnelConnect(ApiControllerParamsInfo param) |         public void Connect(ApiControllerParamsInfo param) | ||||||
|         { |         { | ||||||
|             Task.Run(async () => |             Task.Run(async () => | ||||||
|             { |             { | ||||||
| @@ -110,7 +53,7 @@ namespace cmonitor.plugins.tunnel | |||||||
|                 } |                 } | ||||||
|                 catch (Exception ex) |                 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) |                 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)}"); |                         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."); |             Logger.Instance.Info($"tunnel route level getting."); | ||||||
|             config.Data.Client.Tunnel.RouteLevel = NetworkHelper.GetRouteLevel(out List<IPAddress> ips); |             config.Data.Client.Tunnel.RouteLevel = NetworkHelper.GetRouteLevel(out List<IPAddress> ips); | ||||||
|             Logger.Instance.Info($"tunnel route level:{config.Data.Client.Tunnel.RouteLevel}"); |             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) |         public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies) | ||||||
|         { |         { | ||||||
|             serviceCollection.AddSingleton<TunnelExternalIPServer>(); |  | ||||||
|             serviceCollection.AddSingleton<TunnelServerMessenger>(); |             serviceCollection.AddSingleton<TunnelServerMessenger>(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -53,10 +60,7 @@ namespace cmonitor.plugins.tunnel | |||||||
|  |  | ||||||
|         public void UseServer(ServiceProvider serviceProvider, Config config, Assembly[] assemblies) |         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; |                     continue; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 TunnelTransportInfo tunnelTransportInfo = new TunnelTransportInfo |                 TunnelTransportInfo tunnelTransportInfo = new TunnelTransportInfo | ||||||
|                 { |                 { | ||||||
|                     Direction = TunnelTransportDirection.Forward, |                     Direction = TunnelTransportDirection.Forward, | ||||||
| @@ -80,7 +79,6 @@ namespace cmonitor.plugins.tunnel | |||||||
|                     Local = localInfo, |                     Local = localInfo, | ||||||
|                     Remote = remoteInfo, |                     Remote = remoteInfo, | ||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
|                 TunnelTransportState state = await transport.ConnectAsync(tunnelTransportInfo); |                 TunnelTransportState state = await transport.ConnectAsync(tunnelTransportInfo); | ||||||
|                 if (state != null) |                 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, |                 Connection = clientSignInState.Connection, | ||||||
|                 MessengerId = (ushort)TunnelMessengerIds.BeginForward, |                 MessengerId = (ushort)TunnelMessengerIds.BeginForward, | ||||||
|                 Payload = MemoryPackSerializer.Serialize(tunnelTransportInfo) |                 Payload = MemoryPackSerializer.Serialize(tunnelTransportInfo) | ||||||
|             }); |             }); | ||||||
|  |             return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray); | ||||||
|         } |         } | ||||||
|         private async Task OnSendConnectFail(TunnelTransportInfo tunnelTransportInfo) |         private async Task OnSendConnectFail(TunnelTransportInfo tunnelTransportInfo) | ||||||
|         { |         { | ||||||
|             await messengerSender.SendReply(new MessageRequestWrap |             await messengerSender.SendOnly(new MessageRequestWrap | ||||||
|             { |             { | ||||||
|                 Connection = clientSignInState.Connection, |                 Connection = clientSignInState.Connection, | ||||||
|                 MessengerId = (ushort)TunnelMessengerIds.FailForward, |                 MessengerId = (ushort)TunnelMessengerIds.FailForward, | ||||||
| @@ -185,9 +184,9 @@ namespace cmonitor.plugins.tunnel | |||||||
|         { |         { | ||||||
|             if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG) |             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; |             info.Status = TunnelConnectStatus.Connecting; | ||||||
|             Interlocked.Exchange(ref connectionsChangeFlag, 1); |             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 common.libs.extends; | ||||||
| using MemoryPack; | using MemoryPack; | ||||||
| using System.Net; | using System.Net; | ||||||
| @@ -8,7 +10,16 @@ namespace cmonitor.plugins.tunnel.compact | |||||||
| { | { | ||||||
|     public sealed class CompactSelfHost : ICompact |     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) |         public async Task<TunnelCompactIPEndPoint> GetTcpExternalIPAsync(IPEndPoint server) | ||||||
|         { |         { | ||||||
| @@ -17,23 +28,22 @@ namespace cmonitor.plugins.tunnel.compact | |||||||
|             socket.IPv6Only(server.AddressFamily, false); |             socket.IPv6Only(server.AddressFamily, false); | ||||||
|             await socket.ConnectAsync(server).WaitAsync(TimeSpan.FromSeconds(5)); |             await socket.ConnectAsync(server).WaitAsync(TimeSpan.FromSeconds(5)); | ||||||
|  |  | ||||||
|             byte[] bytes = new byte[128]; |             IConnection connection = tcpServer.BindReceive(socket); | ||||||
|             int length = await socket.ReceiveAsync(bytes.AsMemory(), SocketFlags.None); |             MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap { Connection = connection, MessengerId = (ushort)TunnelMessengerIds.ExternalIP }); | ||||||
|             if (length == 0) |  | ||||||
|             { |             if (resp.Code != MessageResponeCodes.OK) return null; | ||||||
|                 return null; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             IPEndPoint local = socket.LocalEndPoint as IPEndPoint; |             IPEndPoint local = socket.LocalEndPoint as IPEndPoint; | ||||||
|             socket.SafeClose(); |             connection.Disponse(); | ||||||
|             TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(bytes.AsSpan(0,length)); |             TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(resp.Data.Span); | ||||||
|  |  | ||||||
|             return new TunnelCompactIPEndPoint { Local = local, Remote = tunnelExternalIPInfo.ExternalIP }; |             return new TunnelCompactIPEndPoint { Local = local, Remote = tunnelExternalIPInfo.ExternalIP }; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public async Task<TunnelCompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server) |         public async Task<TunnelCompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server) | ||||||
|         { |         { | ||||||
|  |             return null; | ||||||
|  |             /* | ||||||
|             using UdpClient udpClient = new UdpClient(); |             using UdpClient udpClient = new UdpClient(); | ||||||
|             udpClient.Client.Reuse(true); |             udpClient.Client.Reuse(true); | ||||||
|             await udpClient.SendAsync(new byte[1] { 0 }, server); |             await udpClient.SendAsync(new byte[1] { 0 }, server); | ||||||
| @@ -46,6 +56,7 @@ namespace cmonitor.plugins.tunnel.compact | |||||||
|             TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(result.Buffer); |             TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(result.Buffer); | ||||||
|  |  | ||||||
|             return new TunnelCompactIPEndPoint { Local = udpClient.Client.LocalEndPoint as IPEndPoint, Remote = tunnelExternalIPInfo.ExternalIP }; |             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)); |             IEnumerable<Type> types = ReflectionHelper.GetInterfaceSchieves(assembs, typeof(ICompact)); | ||||||
|             types = config.Data.Common.PluginContains(types); |             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) |         public async Task<TunnelCompactIPEndPoint[]> GetExternalIPAsync(ProtocolType protocolType) | ||||||
| @@ -36,7 +36,7 @@ namespace cmonitor.plugins.tunnel.compact | |||||||
|             { |             { | ||||||
|                 TunnelCompactInfo item = config.Data.Client.Tunnel.Servers[i]; |                 TunnelCompactInfo item = config.Data.Client.Tunnel.Servers[i]; | ||||||
|                 if (item.Disabled) continue; |                 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; |                 if (compact == null) continue; | ||||||
|  |  | ||||||
|                 try |                 try | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ namespace cmonitor.plugins.tunnel.compact | |||||||
| { | { | ||||||
|     public interface ICompact |     public interface ICompact | ||||||
|     { |     { | ||||||
|         public string Type { get; } |         public string Name { get; } | ||||||
|         public Task<TunnelCompactIPEndPoint> GetTcpExternalIPAsync(IPEndPoint server); |         public Task<TunnelCompactIPEndPoint> GetTcpExternalIPAsync(IPEndPoint server); | ||||||
|         public Task<TunnelCompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server); |         public Task<TunnelCompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -13,10 +13,7 @@ namespace cmonitor.config | |||||||
|  |  | ||||||
|     public sealed class TunnelConfigClientInfo |     public sealed class TunnelConfigClientInfo | ||||||
|     { |     { | ||||||
|         public TunnelCompactInfo[] Servers { get; set; } = new TunnelCompactInfo[] |         public TunnelCompactInfo[] Servers { get; set; } = Array.Empty<TunnelCompactInfo>(); | ||||||
|         { |  | ||||||
|             new TunnelCompactInfo { Type="self", Host="127.0.0.1:1804" } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         [JsonIgnore] |         [JsonIgnore] | ||||||
|         public int RouteLevel { get; set; } |         public int RouteLevel { get; set; } | ||||||
| @@ -24,12 +21,11 @@ namespace cmonitor.config | |||||||
|  |  | ||||||
|     public sealed class TunnelConfigServerInfo |     public sealed class TunnelConfigServerInfo | ||||||
|     { |     { | ||||||
|         public int ListenPort { get; set; } = 1804; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public sealed class TunnelCompactInfo |     public sealed class TunnelCompactInfo | ||||||
|     { |     { | ||||||
|         public string Type { get; set; } |         public string Name { get; set; } | ||||||
|         public string Host { get; set; } |         public string Host { get; set; } | ||||||
|         public bool Disabled { get; set; } |         public bool Disabled { get; set; } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -2,7 +2,9 @@ | |||||||
| using cmonitor.plugins.tunnel.transport; | using cmonitor.plugins.tunnel.transport; | ||||||
| using cmonitor.server; | using cmonitor.server; | ||||||
| using common.libs; | using common.libs; | ||||||
|  | using common.libs.extends; | ||||||
| using MemoryPack; | using MemoryPack; | ||||||
|  | using System.Net; | ||||||
|  |  | ||||||
| namespace cmonitor.plugins.tunnel.messenger | namespace cmonitor.plugins.tunnel.messenger | ||||||
| { | { | ||||||
| @@ -50,7 +52,6 @@ namespace cmonitor.plugins.tunnel.messenger | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     public sealed class TunnelServerMessenger : IMessenger |     public sealed class TunnelServerMessenger : IMessenger | ||||||
|     { |     { | ||||||
|         private readonly MessengerSender messengerSender; |         private readonly MessengerSender messengerSender; | ||||||
| @@ -90,7 +91,7 @@ namespace cmonitor.plugins.tunnel.messenger | |||||||
|                     MessengerId = (ushort)TunnelMessengerIds.Info, |                     MessengerId = (ushort)TunnelMessengerIds.Info, | ||||||
|                     Payload = connection.ReceiveRequestWrap.Payload |                     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))); |                     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, |         Fail = 2005, | ||||||
|         FailForward = 2006, |         FailForward = 2006, | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         ExternalIP = 2007, | ||||||
|  |  | ||||||
|         None = 2099 |         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> | ||||||
|         /// 发送连接信息 |         /// 发送连接信息 | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         public Func<TunnelTransportInfo, Task> OnSendConnectBegin { get; set; } |         public Func<TunnelTransportInfo, Task<bool>> OnSendConnectBegin { get; set; } | ||||||
|         public Func<TunnelTransportInfo, Task> OnSendConnectFail { get; set; } |         public Func<TunnelTransportInfo, Task> OnSendConnectFail { get; set; } | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// 收到连接信息 |         /// 收到连接信息 | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ namespace cmonitor.plugins.tunnel.transport | |||||||
|         public string Name => "TcpNutssb"; |         public string Name => "TcpNutssb"; | ||||||
|         public ProtocolType Type => ProtocolType.Tcp; |         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 Func<TunnelTransportInfo, Task> OnSendConnectFail { get; set; } = async (info) => { await Task.CompletedTask; }; | ||||||
|         public Action<TunnelTransportInfo> OnConnectBegin { get; set; } = (info) => { }; |         public Action<TunnelTransportInfo> OnConnectBegin { get; set; } = (info) => { }; | ||||||
|         public Action<TunnelTransportInfo> OnConnecting { get; set; } |         public Action<TunnelTransportInfo> OnConnecting { get; set; } | ||||||
| @@ -22,7 +22,6 @@ namespace cmonitor.plugins.tunnel.transport | |||||||
|  |  | ||||||
|  |  | ||||||
|         private readonly TunnelBindServer tunnelBindServer; |         private readonly TunnelBindServer tunnelBindServer; | ||||||
|  |  | ||||||
|         public TransportTcpNutssb(TunnelBindServer tunnelBindServer) |         public TransportTcpNutssb(TunnelBindServer tunnelBindServer) | ||||||
|         { |         { | ||||||
|             this.tunnelBindServer = tunnelBindServer; |             this.tunnelBindServer = tunnelBindServer; | ||||||
| @@ -34,26 +33,30 @@ namespace cmonitor.plugins.tunnel.transport | |||||||
|         { |         { | ||||||
|             OnConnecting(tunnelTransportInfo); |             OnConnecting(tunnelTransportInfo); | ||||||
|  |  | ||||||
|  |             //正向连接 | ||||||
|             tunnelTransportInfo.Direction = TunnelTransportDirection.Forward; |             tunnelTransportInfo.Direction = TunnelTransportDirection.Forward; | ||||||
|             await OnSendConnectBegin(tunnelTransportInfo); |             if (await OnSendConnectBegin(tunnelTransportInfo) == false) | ||||||
|             TunnelTransportState state = await ConnectForward(tunnelTransportInfo); |  | ||||||
|             if (state != null) |  | ||||||
|             { |             { | ||||||
|                 return state; |                 OnConnectFail(tunnelTransportInfo.Remote.MachineName); | ||||||
|  |                 return null; | ||||||
|             } |             } | ||||||
|  |             TunnelTransportState state = await ConnectForward(tunnelTransportInfo); | ||||||
|  |             if (state != null) return state; | ||||||
|  |  | ||||||
|  |             //反向连接 | ||||||
|             TunnelTransportInfo tunnelTransportInfo1 = tunnelTransportInfo.ToJsonFormat().DeJson<TunnelTransportInfo>(); |             TunnelTransportInfo tunnelTransportInfo1 = tunnelTransportInfo.ToJsonFormat().DeJson<TunnelTransportInfo>(); | ||||||
|             tunnelTransportInfo1.Direction = TunnelTransportDirection.Reverse; |             tunnelTransportInfo1.Direction = TunnelTransportDirection.Reverse; | ||||||
|             tunnelBindServer.Bind(tunnelTransportInfo1.Local.Local, tunnelTransportInfo1); |             tunnelBindServer.Bind(tunnelTransportInfo1.Local.Local, tunnelTransportInfo1); | ||||||
|             BindAndTTL(tunnelTransportInfo1); |             BindAndTTL(tunnelTransportInfo1); | ||||||
|             await OnSendConnectBegin(tunnelTransportInfo1); |             if (await OnSendConnectBegin(tunnelTransportInfo1) == false) | ||||||
|  |  | ||||||
|             state = await WaitReverse(tunnelTransportInfo1); |  | ||||||
|             if (state != null) |  | ||||||
|             { |             { | ||||||
|                 return state; |                 OnConnectFail(tunnelTransportInfo.Remote.MachineName); | ||||||
|  |                 return null; | ||||||
|             } |             } | ||||||
|  |             state = await WaitReverse(tunnelTransportInfo1); | ||||||
|  |             if (state != null) return state; | ||||||
|  |  | ||||||
|  |             //正向反向都失败 | ||||||
|             await OnSendConnectFail(tunnelTransportInfo); |             await OnSendConnectFail(tunnelTransportInfo); | ||||||
|             OnConnectFail(tunnelTransportInfo.Remote.MachineName); |             OnConnectFail(tunnelTransportInfo.Remote.MachineName); | ||||||
|             return null; |             return null; | ||||||
| @@ -109,10 +112,10 @@ namespace cmonitor.plugins.tunnel.transport | |||||||
|                 Socket targetSocket = new(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); |                 Socket targetSocket = new(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); | ||||||
|                 targetSocket.IPv6Only(ep.Address.AddressFamily, false); |                 targetSocket.IPv6Only(ep.Address.AddressFamily, false); | ||||||
|                 targetSocket.ReuseBind(new IPEndPoint(ep.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, tunnelTransportInfo.Local.Local.Port)); |                 targetSocket.ReuseBind(new IPEndPoint(ep.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, tunnelTransportInfo.Local.Local.Port)); | ||||||
|  |  | ||||||
|                 IAsyncResult result = targetSocket.BeginConnect(ep, null, null); |                 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) |                     if (result.IsCompleted) | ||||||
|                     { |                     { | ||||||
| @@ -120,6 +123,7 @@ namespace cmonitor.plugins.tunnel.transport | |||||||
|                     } |                     } | ||||||
|                     await Task.Delay(20); |                     await Task.Delay(20); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 try |                 try | ||||||
|                 { |                 { | ||||||
|                     if (result.IsCompleted == false) |                     if (result.IsCompleted == false) | ||||||
| @@ -190,11 +194,19 @@ namespace cmonitor.plugins.tunnel.transport | |||||||
|             TaskCompletionSource<TunnelTransportState> tcs = new TaskCompletionSource<TunnelTransportState>(); |             TaskCompletionSource<TunnelTransportState> tcs = new TaskCompletionSource<TunnelTransportState>(); | ||||||
|             reverseDic.TryAdd(tunnelTransportInfo.Remote.MachineName, tcs); |             reverseDic.TryAdd(tunnelTransportInfo.Remote.MachineName, tcs); | ||||||
|  |  | ||||||
|             TunnelTransportState state = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(3)); |             try | ||||||
|  |             { | ||||||
|             reverseDic.TryRemove(tunnelTransportInfo.Remote.MachineName, out _); |                 TunnelTransportState state = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(3000)); | ||||||
|  |                 return state; | ||||||
|             return state; |             } | ||||||
|  |             catch (Exception) | ||||||
|  |             { | ||||||
|  |             } | ||||||
|  |             finally | ||||||
|  |             { | ||||||
|  |                 reverseDic.TryRemove(tunnelTransportInfo.Remote.MachineName, out _); | ||||||
|  |             } | ||||||
|  |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,6 +21,9 @@ namespace cmonitor.server | |||||||
|         public IPEndPoint Address { get; } |         public IPEndPoint Address { get; } | ||||||
|         public IPEndPoint LocalAddress { get; } |         public IPEndPoint LocalAddress { get; } | ||||||
|  |  | ||||||
|  |         public Socket TcpSourceSocket { get; } | ||||||
|  |         public Socket TcpTargetSocket { get; set; } | ||||||
|  |  | ||||||
|         #region 接收数据 |         #region 接收数据 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// 请求数据包装对象 |         /// 请求数据包装对象 | ||||||
| @@ -41,14 +44,14 @@ namespace cmonitor.server | |||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="data"></param> |         /// <param name="data"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public Task<bool> Send(ReadOnlyMemory<byte> data, bool unconnectedMessage = false); |         public Task<bool> Send(ReadOnlyMemory<byte> data); | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// 发送 |         /// 发送 | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="data"></param> |         /// <param name="data"></param> | ||||||
|         /// <param name="length"></param> |         /// <param name="length"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public Task<bool> Send(byte[] data, int length, bool unconnectedMessage = false); |         public Task<bool> Send(byte[] data, int length); | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// 销毁 |         /// 销毁 | ||||||
| @@ -97,6 +100,9 @@ namespace cmonitor.server | |||||||
|         public IPEndPoint Address { get; protected set; } |         public IPEndPoint Address { get; protected set; } | ||||||
|         public IPEndPoint LocalAddress { 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 接收数据 |         #region 接收数据 | ||||||
|         /// <summary> |         /// <summary> | ||||||
| @@ -194,14 +200,14 @@ namespace cmonitor.server | |||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="data"></param> |         /// <param name="data"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public abstract Task<bool> Send(ReadOnlyMemory<byte> data, bool logger = false); |         public abstract Task<bool> Send(ReadOnlyMemory<byte> data); | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// 发送 |         /// 发送 | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="data"></param> |         /// <param name="data"></param> | ||||||
|         /// <param name="length"></param> |         /// <param name="length"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public abstract Task<bool> Send(byte[] data, int length, bool logger = false); |         public abstract Task<bool> Send(byte[] data, int length); | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// 销毁 |         /// 销毁 | ||||||
| @@ -218,16 +224,16 @@ namespace cmonitor.server | |||||||
|     { |     { | ||||||
|         public TcpConnection(Socket tcpSocket) : base() |         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) |             if (address.Address.AddressFamily == AddressFamily.InterNetworkV6 && address.Address.IsIPv4MappedToIPv6) | ||||||
|             { |             { | ||||||
|                 address = new IPEndPoint(new IPAddress(address.Address.GetAddressBytes()[^4..]), address.Port); |                 address = new IPEndPoint(new IPAddress(address.Address.GetAddressBytes()[^4..]), address.Port); | ||||||
|             } |             } | ||||||
|             Address = address; |             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) |             if (localaddress.Address.AddressFamily == AddressFamily.InterNetworkV6 && localaddress.Address.IsIPv4MappedToIPv6) | ||||||
|             { |             { | ||||||
|                 localaddress = new IPEndPoint(new IPAddress(localaddress.Address.GetAddressBytes()[^4..]), localaddress.Port); |                 localaddress = new IPEndPoint(new IPAddress(localaddress.Address.GetAddressBytes()[^4..]), localaddress.Port); | ||||||
| @@ -238,24 +244,20 @@ namespace cmonitor.server | |||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// 已连接 |         /// 已连接 | ||||||
|         /// </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> | ||||||
|         /// 发送 |         /// 发送 | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="data"></param> |         /// <param name="data"></param> | ||||||
|         /// <returns></returns> |         /// <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) |             if (Connected) | ||||||
|             { |             { | ||||||
|                 try |                 try | ||||||
|                 { |                 { | ||||||
|                     await TcpSocket.SendAsync(data, SocketFlags.None); |                     await TcpSourceSocket.SendAsync(data, SocketFlags.None); | ||||||
|                     //SentBytes += (ulong)data.Length; |                     //SentBytes += (ulong)data.Length; | ||||||
|                     return true; |                     return true; | ||||||
|                 } |                 } | ||||||
| @@ -274,9 +276,9 @@ namespace cmonitor.server | |||||||
|         /// <param name="data"></param> |         /// <param name="data"></param> | ||||||
|         /// <param name="length"></param> |         /// <param name="length"></param> | ||||||
|         /// <returns></returns> |         /// <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> |         /// <summary> | ||||||
|         /// 销毁 |         /// 销毁 | ||||||
| @@ -284,10 +286,13 @@ namespace cmonitor.server | |||||||
|         public override void Disponse() |         public override void Disponse() | ||||||
|         { |         { | ||||||
|             base.Disponse(); |             base.Disponse(); | ||||||
|             if (TcpSocket != null) |             if (TcpSourceSocket != null) | ||||||
|             { |             { | ||||||
|                 TcpSocket.SafeClose(); |                 TcpSourceSocket.SafeClose(); | ||||||
|                 TcpSocket.Dispose(); |                 TcpSourceSocket.Dispose(); | ||||||
|  |  | ||||||
|  |                 TcpTargetSocket?.SafeClose(); | ||||||
|  |                 TcpTargetSocket?.Dispose(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,8 +1,10 @@ | |||||||
| using cmonitor.config; | using cmonitor.config; | ||||||
| using common.libs; | using common.libs; | ||||||
| using common.libs.extends; | using common.libs.extends; | ||||||
|  | using System; | ||||||
| using System.Net; | using System.Net; | ||||||
| using System.Net.Sockets; | using System.Net.Sockets; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
| namespace cmonitor.server | namespace cmonitor.server | ||||||
| { | { | ||||||
| @@ -12,6 +14,8 @@ namespace cmonitor.server | |||||||
|         private Socket socket; |         private Socket socket; | ||||||
|         private UdpClient socketUdp; |         private UdpClient socketUdp; | ||||||
|         private CancellationTokenSource cancellationTokenSource; |         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 Func<IConnection, Task> OnPacket { get; set; } = async (connection) => { await Task.CompletedTask; }; | ||||||
|         public Action<int> OnDisconnected { get; set; } |         public Action<int> OnDisconnected { get; set; } | ||||||
|  |  | ||||||
| @@ -148,17 +152,17 @@ namespace cmonitor.server | |||||||
|                     Connection = CreateConnection(socket) |                     Connection = CreateConnection(socket) | ||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
|                 SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs |                 SocketAsyncEventArgs saea = new SocketAsyncEventArgs | ||||||
|                 { |                 { | ||||||
|                     UserToken = userToken, |                     UserToken = userToken, | ||||||
|                     SocketFlags = SocketFlags.None, |                     SocketFlags = SocketFlags.None, | ||||||
|                 }; |                 }; | ||||||
|                 userToken.PoolBuffer = new byte[bufferSize]; |                 userToken.PoolBuffer = new byte[bufferSize]; | ||||||
|                 readEventArgs.SetBuffer(userToken.PoolBuffer, 0, bufferSize); |                 saea.SetBuffer(userToken.PoolBuffer, 0, bufferSize); | ||||||
|                 readEventArgs.Completed += IO_Completed; |                 saea.Completed += IO_Completed; | ||||||
|                 if (socket.ReceiveAsync(readEventArgs) == false) |                 if (socket.ReceiveAsync(saea) == false) | ||||||
|                 { |                 { | ||||||
|                     ProcessReceive(readEventArgs); |                     ProcessReceive(saea); | ||||||
|                 } |                 } | ||||||
|                 return userToken.Connection; |                 return userToken.Connection; | ||||||
|             } |             } | ||||||
| @@ -179,7 +183,9 @@ namespace cmonitor.server | |||||||
|                 { |                 { | ||||||
|                     int offset = e.Offset; |                     int offset = e.Offset; | ||||||
|                     int length = e.BytesTransferred; |                     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) |                     if (token.Socket.Available > 0) | ||||||
|                     { |                     { | ||||||
| @@ -188,7 +194,8 @@ namespace cmonitor.server | |||||||
|                             length = token.Socket.Receive(e.Buffer); |                             length = token.Socket.Receive(e.Buffer); | ||||||
|                             if (length > 0) |                             if (length > 0) | ||||||
|                             { |                             { | ||||||
|                                 await ReadPacket(token, e.Buffer, 0, length); |                                 res = await ReadPacket(token, e.Buffer, 0, length); | ||||||
|  |                                 if (res == false) return; | ||||||
|                             } |                             } | ||||||
|                             else |                             else | ||||||
|                             { |                             { | ||||||
| @@ -203,7 +210,6 @@ namespace cmonitor.server | |||||||
|                         CloseClientSocket(e); |                         CloseClientSocket(e); | ||||||
|                         return; |                         return; | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     if (token.Socket.ReceiveAsync(e) == false) |                     if (token.Socket.ReceiveAsync(e) == false) | ||||||
|                     { |                     { | ||||||
|                         ProcessReceive(e); |                         ProcessReceive(e); | ||||||
| @@ -222,35 +228,53 @@ namespace cmonitor.server | |||||||
|                 CloseClientSocket(e); |                 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 && length > 4) |  | ||||||
|             { |             { | ||||||
|                 Memory<byte> memory = data.AsMemory(offset, length); |                 if (token.DataBuffer.Size > 0) | ||||||
|                 int packageLen = memory.Span.ToInt32(); |  | ||||||
|                 if (packageLen == length - 4) |  | ||||||
|                 { |                 { | ||||||
|                     token.Connection.ReceiveData = data.AsMemory(offset, packageLen + 4); |                     await token.Connection.TcpTargetSocket.SendAsync(token.DataBuffer.Data.Slice(0, token.DataBuffer.Size), SocketFlags.None); | ||||||
|                     await OnPacket(token.Connection); |                     token.DataBuffer.Clear(); | ||||||
|                     return; |  | ||||||
|                 } |                 } | ||||||
|  |                 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)) | ||||||
|             //不是完整包 |  | ||||||
|             token.DataBuffer.AddRange(data, offset, length); |  | ||||||
|             do |  | ||||||
|             { |             { | ||||||
|                 int packageLen = token.DataBuffer.Data.Span.ToInt32(); |                 return false; | ||||||
|                 if (packageLen > token.DataBuffer.Size - 4) |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 //是一个完整的包 | ||||||
|  |                 if (token.DataBuffer.Size == 0 && length > 4) | ||||||
|                 { |                 { | ||||||
|                     break; |                     Memory<byte> memory = data.AsMemory(offset, length); | ||||||
|  |                     int packageLen = memory.Span.ToInt32(); | ||||||
|  |                     if (packageLen == length - 4) | ||||||
|  |                     { | ||||||
|  |                         token.Connection.ReceiveData = data.AsMemory(offset, packageLen + 4); | ||||||
|  |                         await OnPacket(token.Connection); | ||||||
|  |                         return true; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 token.Connection.ReceiveData = token.DataBuffer.Data.Slice(0, packageLen + 4); |  | ||||||
|                 await OnPacket(token.Connection); |  | ||||||
|  |  | ||||||
|                 token.DataBuffer.RemoveRange(0, packageLen + 4); |                 //不是完整包 | ||||||
|             } while (token.DataBuffer.Size > 4); |                 token.DataBuffer.AddRange(data, offset, length); | ||||||
|  |                 do | ||||||
|  |                 { | ||||||
|  |                     int packageLen = token.DataBuffer.Data.Span.ToInt32(); | ||||||
|  |                     if (packageLen > token.DataBuffer.Size - 4) | ||||||
|  |                     { | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                     token.Connection.ReceiveData = token.DataBuffer.Data.Slice(0, packageLen + 4); | ||||||
|  |                     await OnPacket(token.Connection); | ||||||
|  |  | ||||||
|  |                     token.DataBuffer.RemoveRange(0, packageLen + 4); | ||||||
|  |                 } while (token.DataBuffer.Size > 4); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private void CloseClientSocket(SocketAsyncEventArgs e) |         private void CloseClientSocket(SocketAsyncEventArgs e) | ||||||
| @@ -294,11 +318,14 @@ namespace cmonitor.server | |||||||
|         public Socket Socket { get; set; } |         public Socket Socket { get; set; } | ||||||
|         public ReceiveDataBuffer DataBuffer { get; set; } = new ReceiveDataBuffer(); |         public ReceiveDataBuffer DataBuffer { get; set; } = new ReceiveDataBuffer(); | ||||||
|         public byte[] PoolBuffer { get; set; } |         public byte[] PoolBuffer { get; set; } | ||||||
|  |  | ||||||
|         public void Clear() |         public void Clear() | ||||||
|         { |         { | ||||||
|             Socket?.SafeClose(); |             Connection?.Disponse(); | ||||||
|             Socket = null; |             Socket = null; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             PoolBuffer = Helper.EmptyArray; |             PoolBuffer = Helper.EmptyArray; | ||||||
|  |  | ||||||
|             DataBuffer.Clear(true); |             DataBuffer.Clear(true); | ||||||
|   | |||||||
| @@ -7,6 +7,11 @@ call npm install | |||||||
| call npm run build  | call npm run build  | ||||||
| cd ../  | 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.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.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 | 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 ( | 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\\*" "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" | 	echo F|del  "public\\publish\\%%r\\plugins" | ||||||
| 	rd /s /q "public\\publish\\%%r\\plugins" | 	rd /s /q "public\\publish\\%%r\\plugins" | ||||||
| ) | ) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 snltty
					snltty