diff --git a/NetProxy.Service/NpServiceManager.cs b/NetProxy.Service/NpServiceManager.cs index c43b3b9..dc25de3 100644 --- a/NetProxy.Service/NpServiceManager.cs +++ b/NetProxy.Service/NpServiceManager.cs @@ -1,7 +1,4 @@ using NetProxy.Library; -using NetProxy.Library.Payloads; -using NetProxy.Library.Payloads.ReliableMessages.Notifications; -using NetProxy.Library.Payloads.ReliableMessages.Queries; using NetProxy.Library.Payloads.Routing; using NetProxy.Library.Utilities; using NetProxy.Service.Proxy; @@ -13,351 +10,54 @@ namespace NetProxy.Service { public class NpServiceManager { - private NpConfiguration? _config; - private readonly RmServer _messageServer = new(); + public NpConfiguration? Configuration { get; set; } + private readonly RmServer _messageServer; private readonly NpProxyCollection _proxies = new(); - private readonly HashSet _authenticatedConnections = new(); + public HashSet AuthenticatedConnections { get; set; } = new(); public NpServiceManager() { - _messageServer.OnNotificationReceived += _messageServer_OnNotificationReceived; - _messageServer.OnQueryReceived += _messageServer_OnQueryReceived; - _messageServer.OnDisconnected += _messageServer_OnDisconnected; - } - - private IRmQueryReply _messageServer_OnQueryReceived(RmContext context, IRmPayload payload) - { - if (_authenticatedConnections.Contains(context.ConnectionId) == false) + _messageServer = new RmServer(new RmConfiguration { - var reply = new QueryLoginReply(); - - if (payload is QueryLogin userLogin) - { - try - { - lock (_config.EnsureNotNull()) - { - if (_config.Users.Collection.Where(o => - o.UserName.ToLower() == userLogin.UserName.ToLower() && o.PasswordHash.ToLower() == userLogin.PasswordHash.ToLower()).Any()) - { - _authenticatedConnections.Add(context.ConnectionId); - Console.WriteLine($"Logged in connection: {context.ConnectionId}, User: {userLogin.UserName} (Logged in users {_authenticatedConnections.Count})."); - } - else - { - Console.WriteLine($"Failed login connection: {context.ConnectionId}, User: {userLogin.UserName} (Logged in users {_authenticatedConnections.Count})."); - } - - reply.Result = true; - } - } - catch (Exception ex) - { - Singletons.Logging.Write("An error occurred while logging in.", ex); - reply.Message = ex.Message; - } - - return reply; - } - else - { - throw new Exception("Unhandled pre-login query."); - } - } + Parameter = this + }); - if (payload is QueryProxyConfigurationList) - { - var reply = new QueryProxyConfigurationListReply(); + _messageServer.AddHandler(new NpServiceManagerNotificationHandlers()); + _messageServer.AddHandler(new NpServiceManagerQueryHandlers()); - try - { - lock (_config.EnsureNotNull()) - { - foreach (var proxy in _proxies) - { - var augmentedProxy = new NpProxyGridItem() - { - Id = proxy.Configuration.Id, - Name = proxy.Configuration.Name, - TrafficType = proxy.Configuration.TrafficType, - ProxyType = proxy.Configuration.TrafficType.ToString() + " / " + proxy.Configuration.BindingProtocol.ToString(), - BindingProtocol = proxy.Configuration.BindingProtocol, - Description = proxy.Configuration.Description, - IsRunning = proxy.IsRunning, - ListenPort = proxy.Configuration.ListenPort, - ListenOnAllAddresses = proxy.Configuration.ListenOnAllAddresses, - Bindings = proxy.Configuration.Bindings - }; - - reply.Collection.Add(augmentedProxy); - } - } - - return reply; - } - catch (Exception ex) - { - Singletons.Logging.Write("Failed to get proxy list.", ex); - reply.Message = ex.Message; - } - - return reply; - } - else if (payload is QueryProxyStatistics) - { - var reply = new QueryProxyStatisticsReply(); - - try - { - lock (_config.EnsureNotNull()) - { - foreach (var proxy in _proxies) - { - proxy.Statistics.Use((o) => - { - var statistics = new NpProxyGridStats() - { - Id = proxy.Configuration.Id, - IsRunning = proxy.IsRunning, - BytesRead = o.BytesRead, - BytesWritten = o.BytesWritten, - TotalConnections = o.TotalConnections, - CurrentConnections = o.CurrentConnections - - }; - reply.Collection.Add(statistics); - }); - } - } - - } - catch (Exception ex) - { - Singletons.Logging.Write("Failed to get proxy stats list.", ex); - reply.Message = ex.Message; - } + _messageServer.OnDisconnected += _messageServer_OnDisconnected; + } - return reply; - } - else if (payload is QueryProxyConfiguration proxyRequest) - { - var reply = new QueryProxyConfigurationReply(); + public void Notify(Guid connectionId, IRmNotification notification) + => _messageServer.Notify(connectionId, notification); - try - { - lock (_config.EnsureNotNull()) - { - var proxy = _proxies[proxyRequest.Id]; - if (proxy != null) - { - reply.ProxyConfiguration = proxy.Configuration; - } - } - } - catch (Exception ex) - { - Singletons.Logging.Write("Failed to get proxy.", ex); - reply.Message = ex.Message; - } - return reply; - } - else if (payload is QueryUserList) - { - var reply = new QueryUserListReply(); + public NpProxy? GetProxyById(Guid proxyId) + => _proxies.Where(o => o.Configuration.Id == proxyId).SingleOrDefault(); - try - { - lock (_config.EnsureNotNull()) - { - reply.Collection = _config.Users.Collection; - } - } - catch (Exception ex) - { - Singletons.Logging.Write("Failed to get user list.", ex); - reply.Message = ex.Message; - } + public void AddProxy(NpProxy proxy) + => _proxies.Add(proxy); - return reply; - } + public List GetProxies() + => _proxies.ToList(); - throw new Exception("Unhandled query."); - } + public void RemoveProxy(NpProxy proxy) + => _proxies.Remove(proxy); private void _messageServer_OnDisconnected(RmContext context) { - lock (_config.EnsureNotNull()) - { - _authenticatedConnections.Remove(context.ConnectionId); - } - Console.WriteLine($"Deregistered connection: {context.ConnectionId} (Logged in users {_authenticatedConnections.Count})."); - } - - private void _messageServer_OnNotificationReceived(RmContext context, IRmNotification payload) - { - if (_authenticatedConnections.Contains(context.ConnectionId) == false) - { - if (payload is NotificationRegisterLogin registerLogin) - { - try - { - lock (_config.EnsureNotNull()) - { - if (_config.Users.Collection.Where(o => - o.UserName.ToLower() == registerLogin.UserName.ToLower() && o.PasswordHash.ToLower() == registerLogin.PasswordHash.ToLower()).Any()) - { - _authenticatedConnections.Add(context.ConnectionId); - Console.WriteLine($"Registered connection: {context.ConnectionId}, User: {registerLogin.UserName} (Logged in users {_authenticatedConnections.Count})."); - } - else - { - Console.WriteLine($"Failed to register connection: {context.ConnectionId}, User: {registerLogin.UserName} (Logged in users {_authenticatedConnections.Count})."); - } - } - } - catch (Exception ex) - { - Singletons.Logging.Write("An error occurred while logging in.", ex); - } - } - else - { - throw new Exception("Unhandled pre-login notification."); - } - - return; //If the peer is not logged in, don't go any further. - } - - if (payload is NotificationPersistUserList persistUserList) - { - try - { - lock (_config.EnsureNotNull()) - { - _config.Users.Collection.Clear(); - - foreach (var user in persistUserList.Collection) - { - _config.Users.Add(user); - } - SaveConfiguration(); - } - } - catch (Exception ex) - { - Singletons.Logging.Write("Failed to save user list.", ex); - } - } - else if (payload is NotificationUpsertProxy persistUpsertProxy) - { - try - { - - lock (_config.EnsureNotNull()) - { - var existingProxy = (from o in _proxies - where o.Configuration.Id == persistUpsertProxy.ProxyConfiguration.Id - select o).FirstOrDefault(); - - if (existingProxy != null) - { - existingProxy.Stop(); - _proxies.Remove(existingProxy); - } - - var newProxy = new NpProxy(persistUpsertProxy.ProxyConfiguration); - - _proxies.Add(newProxy); - - SaveConfiguration(); - - if (newProxy.Configuration.AutoStart) - { - newProxy.Start(); - } - } - } - catch (Exception ex) - { - Singletons.Logging.Write("Failed to upsert proxy.", ex); - } - } - else if (payload is NotificationDeleteProxy persistDeleteProxy) - { - try - { - - lock (_config.EnsureNotNull()) - { - var existingProxy = (from o in _proxies - where o.Configuration.Id == persistDeleteProxy.Id - select o).FirstOrDefault(); - - if (existingProxy != null) - { - existingProxy.Stop(); - _proxies.Remove(existingProxy); - } - SaveConfiguration(); - } - } - catch (Exception ex) - { - Singletons.Logging.Write("Failed to delete proxy.", ex); - } - } - else if (payload is NotificationStopProxy persistStopProxy) - { - try - { - lock (_config.EnsureNotNull()) - { - var existingProxy = (from o in _proxies - where o.Configuration.Id == persistStopProxy.Id - select o).FirstOrDefault(); - - existingProxy?.Stop(); - } - } - catch (Exception ex) - { - Singletons.Logging.Write("Failed to stop proxy.", ex); - } - } - else if (payload is NotificationStartProxy persistStartProxy) - { - try - { - - lock (_config.EnsureNotNull()) - { - var existingProxy = (from o in _proxies - where o.Configuration.Id == persistStartProxy.Id - select o).FirstOrDefault(); - - if (existingProxy?.Start() != true) - { - _messageServer.Notify(context.ConnectionId, new NotificationMessage("Failed to start proxy.")); - } - } - } - catch (Exception ex) - { - Singletons.Logging.Write("Failed to start proxy.", ex); - } - } - else + lock (Configuration.EnsureNotNull()) { - throw new Exception("Unhandled notification."); + AuthenticatedConnections.Remove(context.ConnectionId); } + Console.WriteLine($"Deregistered connection: {context.ConnectionId} (Logged in users {AuthenticatedConnections.Count})."); } public void SaveConfiguration() { try { - CommonApplicationData.SaveToDisk(Constants.FriendlyName, _config); + CommonApplicationData.SaveToDisk(Constants.FriendlyName, Configuration); CommonApplicationData.SaveToDisk(Constants.FriendlyName, _proxies.CloneConfigurations()); } catch (Exception ex) @@ -390,7 +90,7 @@ public void LoadConfiguration() }); Console.WriteLine("Server configuration..."); - _config = CommonApplicationData.LoadFromDisk(Constants.FriendlyName, defaultConfiguration); + Configuration = CommonApplicationData.LoadFromDisk(Constants.FriendlyName, defaultConfiguration); Console.WriteLine("Proxy configuration..."); var proxies = CommonApplicationData.LoadFromDisk(Constants.FriendlyName, new List()); @@ -491,8 +191,8 @@ public void Start() { LoadConfiguration(); - Console.WriteLine("Starting management interface on port {0}.", _config.EnsureNotNull().ManagementPort); - _messageServer.Start(_config.ManagementPort); + Console.WriteLine("Starting management interface on port {0}.", Configuration.EnsureNotNull().ManagementPort); + _messageServer.Start(Configuration.ManagementPort); Console.WriteLine("starting proxies..."); _proxies.Start(); diff --git a/NetProxy.Service/NpServiceManagerMessageHandlerBase.cs b/NetProxy.Service/NpServiceManagerMessageHandlerBase.cs new file mode 100644 index 0000000..83c4b56 --- /dev/null +++ b/NetProxy.Service/NpServiceManagerMessageHandlerBase.cs @@ -0,0 +1,19 @@ +using NTDLS.NullExtensions; +using NTDLS.ReliableMessaging; + +namespace NetProxy.Service +{ + internal class NpServiceManagerMessageHandlerBase + { + public NpServiceManager EnforceLoginAndGetServiceManager(RmContext context) + { + var serviceManager = (context.Endpoint.Parameter as NpServiceManager).EnsureNotNull(); + if (serviceManager.AuthenticatedConnections.Contains(context.ConnectionId) == false) + { + throw new Exception("Login has not been completed."); + } + return serviceManager; + } + + } +} \ No newline at end of file diff --git a/NetProxy.Service/NpServiceManagerNotificationHandlers.cs b/NetProxy.Service/NpServiceManagerNotificationHandlers.cs new file mode 100644 index 0000000..1846e9a --- /dev/null +++ b/NetProxy.Service/NpServiceManagerNotificationHandlers.cs @@ -0,0 +1,166 @@ +using NetProxy.Library.Payloads.ReliableMessages.Notifications; +using NetProxy.Library.Utilities; +using NetProxy.Service.Proxy; +using NTDLS.NullExtensions; +using NTDLS.ReliableMessaging; + +namespace NetProxy.Service +{ + internal class NpServiceManagerNotificationHandlers : NpServiceManagerMessageHandlerBase, IRmMessageHandler + { + public void OnNotificationRegisterLogin(RmContext context, NotificationRegisterLogin notification) + { + var serviceManager = (context.Endpoint.Parameter as NpServiceManager).EnsureNotNull(); + + try + { + lock (serviceManager.Configuration.EnsureNotNull()) + { + if (serviceManager.Configuration.Users.Collection.Where(o => + o.UserName.ToLower() == notification.UserName.ToLower() && o.PasswordHash.ToLower() == notification.PasswordHash.ToLower()).Any()) + { + serviceManager.AuthenticatedConnections.Add(context.ConnectionId); + + Singletons.Logging.Write(NpLogging.Severity.Verbose, + $"Registered connection: {context.ConnectionId}, User: {notification.UserName} (Logged in users {serviceManager.AuthenticatedConnections.Count})."); + } + else + { + Singletons.Logging.Write(NpLogging.Severity.Verbose, + $"Failed to register connection: {context.ConnectionId}, User: {notification.UserName} (Logged in users {serviceManager.AuthenticatedConnections.Count})."); + } + } + } + catch (Exception ex) + { + Singletons.Logging.Write("An error occurred while logging in.", ex); + } + } + + public void OnNotificationPersistUserList(RmContext context, NotificationPersistUserList notification) + { + var serviceManager = EnforceLoginAndGetServiceManager(context); + + try + { + lock (serviceManager.Configuration.EnsureNotNull()) + { + serviceManager.Configuration.Users.Collection.Clear(); + + foreach (var user in notification.Collection) + { + serviceManager.Configuration.Users.Add(user); + } + serviceManager.SaveConfiguration(); + } + } + catch (Exception ex) + { + Singletons.Logging.Write("Failed to save user list.", ex); + } + + } + + public void OnNotificationUpsertProxy(RmContext context, NotificationUpsertProxy notification) + { + var serviceManager = EnforceLoginAndGetServiceManager(context); + + try + { + + lock (serviceManager.Configuration.EnsureNotNull()) + { + var existingProxy = serviceManager.GetProxyById(notification.ProxyConfiguration.Id); + + if (existingProxy != null) + { + existingProxy.Stop(); + serviceManager.RemoveProxy(existingProxy); + } + + var newProxy = new NpProxy(notification.ProxyConfiguration); + + serviceManager.AddProxy(newProxy); + + serviceManager.SaveConfiguration(); + + if (newProxy.Configuration.AutoStart) + { + newProxy.Start(); + } + } + } + catch (Exception ex) + { + Singletons.Logging.Write("Failed to upsert proxy.", ex); + } + + } + + public void OnNotificationDeleteProxy(RmContext context, NotificationDeleteProxy notification) + { + var serviceManager = EnforceLoginAndGetServiceManager(context); + + try + { + + lock (serviceManager.Configuration.EnsureNotNull()) + { + var existingProxy = serviceManager.GetProxyById(notification.Id); + + if (existingProxy != null) + { + existingProxy.Stop(); + serviceManager.RemoveProxy(existingProxy); + } + serviceManager.SaveConfiguration(); + } + } + catch (Exception ex) + { + Singletons.Logging.Write("Failed to delete proxy.", ex); + } + } + + public void OnNotificationStopProxy(RmContext context, NotificationStopProxy notification) + { + var serviceManager = EnforceLoginAndGetServiceManager(context); + + try + { + lock (serviceManager.Configuration.EnsureNotNull()) + { + var existingProxy = serviceManager.GetProxyById(notification.Id); + + existingProxy?.Stop(); + } + } + catch (Exception ex) + { + Singletons.Logging.Write("Failed to stop proxy.", ex); + } + } + + public void OnNotificationStartProxy(RmContext context, NotificationStartProxy notification) + { + var serviceManager = EnforceLoginAndGetServiceManager(context); + + try + { + lock (serviceManager.Configuration.EnsureNotNull()) + { + var existingProxy = serviceManager.GetProxyById(notification.Id); + + if (existingProxy?.Start() != true) + { + serviceManager.Notify(context.ConnectionId, new NotificationMessage("Failed to start proxy.")); + } + } + } + catch (Exception ex) + { + Singletons.Logging.Write("Failed to start proxy.", ex); + } + } + } +} diff --git a/NetProxy.Service/NpServiceManagerQueryHandlers.cs b/NetProxy.Service/NpServiceManagerQueryHandlers.cs new file mode 100644 index 0000000..5d4ca35 --- /dev/null +++ b/NetProxy.Service/NpServiceManagerQueryHandlers.cs @@ -0,0 +1,175 @@ +using NetProxy.Library.Payloads; +using NetProxy.Library.Payloads.ReliableMessages.Queries; +using NetProxy.Library.Utilities; +using NTDLS.NullExtensions; +using NTDLS.ReliableMessaging; + +namespace NetProxy.Service +{ + internal class NpServiceManagerQueryHandlers : NpServiceManagerMessageHandlerBase, IRmMessageHandler + { + public QueryLoginReply OnQueryLogin(RmContext context, QueryLogin query) + { + var serviceManager = (context.Endpoint.Parameter as NpServiceManager).EnsureNotNull(); + + var reply = new QueryLoginReply(); + + try + { + lock (serviceManager.Configuration.EnsureNotNull()) + { + if (serviceManager.Configuration.Users.Collection.Where(o => + o.UserName.Equals(query.UserName, StringComparison.CurrentCultureIgnoreCase) + && o.PasswordHash.Equals(query.PasswordHash, StringComparison.CurrentCultureIgnoreCase)).Any()) + { + serviceManager.AuthenticatedConnections.Add(context.ConnectionId); + Singletons.Logging.Write(NpLogging.Severity.Verbose, + $"Logged in connection: {context.ConnectionId}, User: {query.UserName} (Logged in users {serviceManager.AuthenticatedConnections.Count})."); + } + else + { + Singletons.Logging.Write(NpLogging.Severity.Verbose, + $"Failed login connection: {context.ConnectionId}, User: {query.UserName} (Logged in users {serviceManager.AuthenticatedConnections.Count})."); + } + + reply.Result = true; + } + } + catch (Exception ex) + { + Singletons.Logging.Write("An error occurred while logging in.", ex); + reply.Message = ex.Message; + } + + return reply; + } + + public QueryProxyConfigurationListReply OnQueryProxyConfigurationList(RmContext context, QueryProxyConfigurationList query) + { + var serviceManager = EnforceLoginAndGetServiceManager(context); + + var reply = new QueryProxyConfigurationListReply(); + + try + { + lock (serviceManager.Configuration.EnsureNotNull()) + { + foreach (var proxy in serviceManager.GetProxies()) + { + var augmentedProxy = new NpProxyGridItem() + { + Id = proxy.Configuration.Id, + Name = proxy.Configuration.Name, + TrafficType = proxy.Configuration.TrafficType, + ProxyType = proxy.Configuration.TrafficType.ToString() + " / " + proxy.Configuration.BindingProtocol.ToString(), + BindingProtocol = proxy.Configuration.BindingProtocol, + Description = proxy.Configuration.Description, + IsRunning = proxy.IsRunning, + ListenPort = proxy.Configuration.ListenPort, + ListenOnAllAddresses = proxy.Configuration.ListenOnAllAddresses, + Bindings = proxy.Configuration.Bindings + }; + + reply.Collection.Add(augmentedProxy); + } + } + + return reply; + } + catch (Exception ex) + { + Singletons.Logging.Write("Failed to get proxy list.", ex); + reply.Message = ex.Message; + } + + return reply; + } + + public QueryProxyStatisticsReply OnQueryProxyStatistics(RmContext context, QueryProxyStatistics query) + { + var serviceManager = EnforceLoginAndGetServiceManager(context); + + var reply = new QueryProxyStatisticsReply(); + + try + { + lock (serviceManager.Configuration.EnsureNotNull()) + { + foreach (var proxy in serviceManager.GetProxies()) + { + proxy.Statistics.Use((o) => + { + var statistics = new NpProxyGridStats() + { + Id = proxy.Configuration.Id, + IsRunning = proxy.IsRunning, + BytesRead = o.BytesRead, + BytesWritten = o.BytesWritten, + TotalConnections = o.TotalConnections, + CurrentConnections = o.CurrentConnections + + }; + reply.Collection.Add(statistics); + }); + } + } + + } + catch (Exception ex) + { + Singletons.Logging.Write("Failed to get proxy stats list.", ex); + reply.Message = ex.Message; + } + + return reply; + } + + public QueryProxyConfigurationReply OnQueryProxyConfiguration(RmContext context, QueryProxyConfiguration query) + { + var serviceManager = EnforceLoginAndGetServiceManager(context); + + var reply = new QueryProxyConfigurationReply(); + + try + { + lock (serviceManager.Configuration.EnsureNotNull()) + { + var proxy = serviceManager.GetProxyById(query.Id); + if (proxy != null) + { + reply.ProxyConfiguration = proxy.Configuration; + } + } + } + catch (Exception ex) + { + Singletons.Logging.Write("Failed to get proxy.", ex); + reply.Message = ex.Message; + } + + return reply; + } + + public QueryUserListReply OnQueryUserList(RmContext context, QueryUserList query) + { + var serviceManager = EnforceLoginAndGetServiceManager(context); + + var reply = new QueryUserListReply(); + + try + { + lock (serviceManager.Configuration.EnsureNotNull()) + { + reply.Collection = serviceManager.Configuration.Users.Collection; + } + } + catch (Exception ex) + { + Singletons.Logging.Write("Failed to get user list.", ex); + reply.Message = ex.Message; + } + + return reply; + } + } +} diff --git a/NetProxy.Service/Proxy/NpProxyCollection.cs b/NetProxy.Service/Proxy/NpProxyCollection.cs index d6f4776..c25f54b 100644 --- a/NetProxy.Service/Proxy/NpProxyCollection.cs +++ b/NetProxy.Service/Proxy/NpProxyCollection.cs @@ -12,12 +12,6 @@ public List CloneConfigurations() return proxyConfigurations; } - public NpProxy? this[Guid proxyId] - => this.Where(o => o.Configuration.Id == proxyId).FirstOrDefault(); - - //public void Add(NpProxy proxy) - // => this.Add(proxy); - public new void Remove(NpProxy item) { NpUtility.TryAndIgnore(item.Stop); diff --git a/NetProxy.Service/Proxy/NpProxyConnection.cs b/NetProxy.Service/Proxy/NpProxyConnection.cs index d9f1908..ee64c07 100644 --- a/NetProxy.Service/Proxy/NpProxyConnection.cs +++ b/NetProxy.Service/Proxy/NpProxyConnection.cs @@ -8,6 +8,9 @@ namespace NetProxy.Service.Proxy { + /// + /// This is an endpoint, it contains all of the logic to serve both an inbound and an outbound connection. + /// internal class NpProxyConnection { public ConnectionDirection Direction { get; private set; } @@ -34,15 +37,15 @@ public NpProxyConnection(NpProxyListener listener, TcpClient tcpClient) _stream = tcpClient.GetStream(); } - public void Write(byte[] buffer) + public void WriteBytesToPeer(byte[] buffer) { if (_outboundEndpoint != null) { _listener.EndpointStatistics.Use((o) => { - if (o.ContainsKey(_outboundEndpoint.Id)) + if (o.TryGetValue(_outboundEndpoint.Id, out NpProxyEndpointStatistics? value)) { - o[_outboundEndpoint.Id].BytesWritten += (ulong)buffer.Length; + value.BytesWritten += (ulong)buffer.Length; } }); } @@ -52,15 +55,15 @@ public void Write(byte[] buffer) _stream.Write(buffer); } - public void Write(byte[] buffer, int length) + public void WriteBytesToPeer(byte[] buffer, int length) { if (_outboundEndpoint != null) { _listener.EndpointStatistics.Use((o) => { - if (o.ContainsKey(_outboundEndpoint.Id)) + if (o.TryGetValue(_outboundEndpoint.Id, out NpProxyEndpointStatistics? value)) { - o[_outboundEndpoint.Id].BytesWritten += (ulong)length; + value.BytesWritten += (ulong)length; } }); } @@ -70,7 +73,7 @@ public void Write(byte[] buffer, int length) _stream.Write(buffer, 0, length); } - public bool Read(ref byte[] buffer, out int outBytesRead) + public bool ReadBytesFromPeer(ref byte[] buffer, out int outBytesRead) { LastActivityDateTime = DateTime.UtcNow; int bytesRead = _stream.Read(buffer, 0, buffer.Length); @@ -93,9 +96,9 @@ public bool Read(ref byte[] buffer, out int outBytesRead) } /// - /// We received an inbound connection which is now open and ready. This is where we establish the connection to the associated endpoint. + /// We received an inbound connection which is now open and ready. + /// This is where we establish the connection to the associated outbound endpoint. /// - /// public void RunInboundAsync() { Direction = ConnectionDirection.Inbound; @@ -122,6 +125,7 @@ public void RunInboundAsync() TcpClient? establishedConnection = null; #region First try sticky sessions.... + if (_listener.Proxy.Configuration.UseStickySessions) { if (_listener.StickySessionCache.TryGetValue(sessionKey, out NpStickySession? cacheItem) && cacheItem != null) @@ -144,6 +148,7 @@ public void RunInboundAsync() } } } + #endregion //If and while we do not have a connection, lets determine what endpoint we should use. @@ -225,6 +230,8 @@ public void RunInboundAsync() _listener.StickySessionCache.Set(sessionKey, new NpStickySession(endpoint.Address, endpoint.Port)); } + Singletons.Logging.Write(NpLogging.Severity.Verbose, $"Outbound endpoint connection was established: {endpoint.Id}"); + _peer = new NpProxyConnection(_listener, establishedConnection); _peer.RunOutboundAsync(this, endpoint); @@ -232,6 +239,9 @@ public void RunInboundAsync() _dataPumpThread.Start(); } + /// + /// Pump data for the outbound endpoint. + /// public void RunOutboundAsync(NpProxyConnection peer, NpEndpoint endpoint) { Direction = ConnectionDirection.Outbound; @@ -250,9 +260,8 @@ internal void DataPumpThreadProc() { _listener.EndpointStatistics.Use((o) => { - if (o.ContainsKey(_outboundEndpoint.Id)) + if (o.TryGetValue(_outboundEndpoint.Id, out NpProxyEndpointStatistics? stat)) { - var stat = o[_outboundEndpoint.Id]; stat.CurrentConnections++; stat.TotalConnections++; } @@ -266,7 +275,7 @@ internal void DataPumpThreadProc() StringBuilder? httpRequestHeaderBuilder = null; - while (_keepRunning && Read(ref buffer, out int bufferLength)) + while (_keepRunning && ReadBytesFromPeer(ref buffer, out int bufferLength)) { #region HTTP Header augmentation. @@ -353,7 +362,7 @@ internal void DataPumpThreadProc() httpRequestHeaderBuilder = null; //We have completed reconstructing the header and performed modifications. //Send the modified header to the peer. - _peer?.Write(Encoding.UTF8.GetBytes(modifiedHttpRequestHeader)); + _peer?.WriteBytesToPeer(Encoding.UTF8.GetBytes(modifiedHttpRequestHeader)); if (bufferLength == 0) { @@ -372,7 +381,7 @@ internal void DataPumpThreadProc() #endregion - _peer?.Write(buffer, bufferLength); //Send data to remote peer. + _peer?.WriteBytesToPeer(buffer, bufferLength); //Send data to remote peer. #region Buffer resize. if (bufferLength == buffer.Length && buffer.Length < _listener.Proxy.Configuration.MaxBufferSize) diff --git a/NetProxy.Service/Proxy/NpProxyListener.cs b/NetProxy.Service/Proxy/NpProxyListener.cs index 596c8c5..f90653d 100644 --- a/NetProxy.Service/Proxy/NpProxyListener.cs +++ b/NetProxy.Service/Proxy/NpProxyListener.cs @@ -102,6 +102,8 @@ void InboundListenerThreadProc() }); Singletons.Logging.Write(NpLogging.Severity.Verbose, $"Accepted inbound endpoint connection: {activeConnection.Id}"); + + //This starts the process of establishing the associated outbound connection and pumping data. activeConnection.RunInboundAsync(); } }