SocketHandlerBase.cs
#region Using
using System.Text; using System.Net.Sockets; using Ninject; using GenXdev.AsyncSockets.Additional; using GenXdev.Configuration; using System.Collections.Concurrent; using GenXdev.MemoryManagement; using GenXdev.AsyncSockets.Containers; using GenXdev.Additional; using System.Net.Security; using GenXdev.Buffers; using Org.BouncyCastle.Asn1.X509; using System.Security.Cryptography.X509Certificates; using GenXdev.Helpers; using System.Reflection; using GenXdev.AsyncSockets.Arguments; using System.Security.Authentication; using System.Net; #endregion namespace GenXdev.AsyncSockets.Handlers { public delegate void LockCallback(); /// <summary> /// Baseclass for asynchronous socket communication controllers /// </summary> public class SocketHandlerBase : IDisposable { #region Initialization / Finalization /// <summary> /// Reference to Ninject service kernel /// </summary> protected IKernel Kernel { get; private set; } /// <summary> /// Reference to global memory manager /// </summary> protected IServiceMemoryManager MemoryManager { get; private set; } /// <summary> /// Assigned memory configuration for this socket handler /// </summary> public IMemoryManagerConfiguration MemoryConfiguration { get; private set; } /// <summary> /// Servicename category of this socket handler /// </summary> public String ServiceName { get; private set; } internal ISocketIOHandler SocketIO; #if(Logging) /// <summary> /// Servicelogger for debug logging /// </summary> protected internal IServiceLogger Logger { get; private set; } #endif /// <summary> /// The socket handler pool, if any, associated with this socket handler /// </summary> protected object Pool { get; private set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors"), Inject] public SocketHandlerBase( IKernel Kernel , IMemoryManagerConfiguration MemoryConfiguration , IServiceMemoryManager MemoryManager , String ServiceName #if (Logging) , IServiceLogger Logger #endif , object Pool = null ) { this.Kernel = Kernel; this.MemoryConfiguration = MemoryConfiguration; this.MemoryManager = MemoryManager; this.ServiceName = ServiceName; this.Pool = Pool; LastActivityTimeStamp = BitConverter.DoubleToInt64Bits(Timer.Duration); #if (Logging) this.Logger = Logger; #endif SetActivityTimestamp(); PollTimer = new System.Threading.Timer(new TimerCallback(ClearPollIngStateAndContinue), this, Timeout.Infinite, Timeout.Infinite); this.rxBuffer = Kernel.Get<DynamicBuffer>(); this.txBuffer = Kernel.Get<DynamicBuffer>(); this.SocketIO = new SocketIOHandler(); SetupHandlers(); } /// <summary> /// Descendents classes should implement this method to assign the initial eventhandlers for handling this socket /// </summary> protected virtual void SetupHandlers() { } /// <summary> /// Used internally to create a new socket event argument instance /// </summary> internal protected void CreateSaea() { DisposeSaea(); // var saeaBufferSize = Math.Max(MemoryConfiguration.ReceiveBufferSize, MemoryConfiguration.SendBufferSize); saeaHandler = new SocketAsyncEventArgs(); saeaHandler.SetHandler(this); // saeaHandler.SetBuffer(0, saeaBufferSize); } internal protected void DisposeSaea() { if (saeaHandler != null) { SocketIO.Unregister(saeaHandler); saeaHandler.SetHandler(null); saeaHandler.Dispose(); saeaHandler = null; } } /// <summary> /// Disposes this socket handler instance /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing && !IsDisposed) { IsDisposed = true; if (saeaHandler != null) { DisposeSaea(); } this.SocketIO = null; this.OnHandlerClosed = null; StopSsl(); if (PollTimer != null) { PollTimer.Dispose(); PollTimer = null; } if (SslAdapter != null) { SslAdapter.Dispose(); SslAdapter = null; } if (rxBuffer != null) { rxBuffer.Dispose(); rxBuffer = null; } if (txBuffer != null) { txBuffer.Dispose(); txBuffer = null; } OnHandleCapturedSocketDisconnectSuccess = null; OnHandleCapturedSocketInitialize = null; OnHandleCapturedSocketReceiveSuccess = null; OnHandleCapturedSocketReset = null; OnHandleCapturedSocketSendSuccess = null; OnHandleCaptureRelease = null; OnHandleConnect = null; OnHandleDisconnect = null; OnHandleException = null; OnHandleInitialize = null; OnHandleNewMessage = null; OnHandlePoll = null; OnHandleAsyncAction = null; OnHandleReceive = null; OnHandleReset = null; OnHandleSend = null; } } ~SocketHandlerBase() { Dispose(false); } #endregion #region Fields public static GenXdev.Additional.HiPerfTimer.NativeMethods Timer = new GenXdev.Additional.HiPerfTimer.NativeMethods(true); #region Private internal static long _NextUniqueIdx = 0; private object _UniqueSocketIdLock = new object(); internal protected long UniqueSocketId { get { lock (_UniqueSocketIdLock) { return _UniqueSocketId; } } internal set { lock (_UniqueSocketIdLock) { _UniqueSocketId = value; } } } bool IsDisposed; SslStream SslConversionStream; AsyncSocketHandlerTlsStreamAdapter SslAdapter; public DynamicBuffer rxBuffer { get; private set; } public DynamicBuffer txBuffer { get; private set; } internal Queue<SocketHandlerBase> CaptureRequestQueue = new Queue<SocketHandlerBase>(4); internal Queue<object> MessageQueue = new Queue<object>(4); internal volatile bool IsCaptured; internal volatile SocketHandlerBase _CapturingHandler; internal volatile bool IsInAsyncCall; public event EventHandler<HandlerClosedEventArgs> OnHandlerClosed; volatile public SocketAsyncEventArgs saeaHandler; static byte[] dummyPacket = new byte[1]; internal protected long CurrentStageTimeout = BitConverter.DoubleToInt64Bits(20d); internal protected long LastActivityTimeStamp; long _HandlerState = 3; protected Double HandlerStartTimestamp { get; private set; } protected internal volatile bool AutoResetTimeouts; object PollingStateLock = new object(); System.Threading.Timer PollTimer; long _PollingState = 0; ConcurrentDictionary<string, List<SocketHandlerBase>> SignalWaiteners = new ConcurrentDictionary<string, List<SocketHandlerBase>>(); ConcurrentDictionary<string, List<SocketHandlerBase>> SignalSuppliers = new ConcurrentDictionary<string, List<SocketHandlerBase>>(); #endregion #endregion # region Transport security /// <summary> /// Starts TLS with a auto generated, and then cached, self-signed certificate /// </summary> public async Task StartSslAsServer() { if (SslStarted) return; // init string issuerName = "Self-signed"; // determine what assembly to use for companyname var assembly = Assembly.GetEntryAssembly(); if (assembly == null) assembly = Assembly.GetAssembly(this.GetType()); // get companyname var attributes = assembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); if (attributes.Length > 0) { var attribute = attributes[0] as AssemblyCompanyAttribute; issuerName = attribute.Company; } // delegate await StartSslAsServer(ServiceName, issuerName); } /// <summary> /// Starts TLS with a auto generated, and then cached, self-signed certificate /// </summary> /// <param name="targetHost">The name of the self-signed authority</param> /// <param name="issuerName">The subject for this certificate, e.g. domainname</param> public async Task StartSslAsServer(string targetHost, string issuerName) { if (SslStarted) return; // delegate await _StartSslAsServer(targetHost, issuerName); } /// <summary> /// Starts TLS with a auto generated, and then cached, self-signed certificate /// </summary> /// <param name="targetHost">The name of the self-signed authority</param> /// <param name="issuerName">The subject for this certificate, e.g. domainname</param> async Task _StartSslAsServer(string targetHost, string issuerName, SslProtocols enabledSslProtocols = SslProtocols.Tls12) { if (SslStarted) return; // prevent timeout SetCurrentStageTimeoutSeconds(50, true); SetActivityTimestamp(); // require encryption var EncryptionPolicy = System.Net.Security.EncryptionPolicy.RequireEncryption; // init flags bool clientCertificateRequired = false; bool checkCertificateRevocation = false; // load or create server certificate serverCertificate = LoadOrCreateServerCertificate(ServiceName, targetHost, new[] { Dns.GetHostName().ToLower(), GenXdev.Helpers.Network.GetPublicExternalHostname(((IPEndPoint)saeaHandler.AcceptSocket.LocalEndPoint).ToString()) }, new[] { KeyPurposeID.id_kp_serverAuth, KeyPurposeID.id_kp_emailProtection, KeyPurposeID.id_kp_clientAuth }, issuerName ); // delegate await StartSslAsServer(targetHost, enabledSslProtocols, EncryptionPolicy, clientCertificateRequired, OnSelectLocalCertificate, checkCertificateRevocation, OnValidateRemoteCertificate, serverCertificate, null); } /// <summary> /// Starts TLS with a auto generated, and then cached, self-signed certificate /// </summary> /// <param name="PFXFilePath">Filepath to a PFX certificate file</param> /// <param name="Password">The password for this certificate</param> public async Task StartSslAsServerWithCertificateFromFile(string PFXFilePath, string Password = null) { if (SslStarted) return; // prevent timeout SetCurrentStageTimeoutSeconds(50, true); SetActivityTimestamp(); lock (sslCertificates) // try to find certificate from the local memory cache if (!sslCertificates.TryGetValue(PFXFilePath, out serverCertificate)) { // not found! // setup file path if (!Path.IsPathRooted(PFXFilePath)) { PFXFilePath = Path.Combine(GenXdev.Helpers.Environment.GetAssemblyRootDirectory(), PFXFilePath); } // does not exist? if (!File.Exists(PFXFilePath)) { throw new InvalidOperationException("Could not find certificate file \"" + PFXFilePath + "\""); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Loading server certificate"; }); #endif #endregion ------------------------------------------------------------------------------------------------ serverCertificate = new X509Certificate2( File.ReadAllBytes(PFXFilePath), Password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet ); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Server certificate loaded"; }); #endif #endregion ------------------------------------------------------------------------------------------------ // add to local memory cache sslCertificates.AddOrUpdate(PFXFilePath, serverCertificate, (key, oldValue) => serverCertificate); } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Server certificate loaded from cache"; }); #endif #endregion ------------------------------------------------------------------------------------------------ } // failed? if (serverCertificate == null) { throw new InvalidOperationException("Could not find any certificate in file \"" + PFXFilePath + "\""); } // by default only the latest version var enabledSslProtocols = SslProtocols.Tls12; // require encryption var EncryptionPolicy = System.Net.Security.EncryptionPolicy.RequireEncryption; // init flags bool clientCertificateRequired = false; bool checkCertificateRevocation = false; // delegate await StartSslAsServer(serverCertificate.Subject, enabledSslProtocols, EncryptionPolicy, clientCertificateRequired, OnSelectLocalCertificate, checkCertificateRevocation, OnValidateRemoteCertificate, serverCertificate, null); } /// <summary> /// Called by servers to begin an asynchronous operation to authenticate the server and optionally the client using the specified certificates, requirements and security protocol. /// </summary> /// <param name="targetHost"></param> /// <param name="enabledSslProtocols">The System.Security.Authentication.SslProtocols value that represents the protocol used for authentication</param> /// <param name="EncryptionPolicy">The EncryptionPolicy to use</param> /// <param name="clientCertificateRequired">A System.Boolean value that specifies whether the client must supply a certificate for authentication.</param> /// <param name="OnSelectLocalCertificate">Selects the local Secure Sockets Layer (SSL) certificate used for authentication.</param> /// <param name="checkCertificateRevocation">Indicates if the remote certificate needs to be checked against a official certificate authority</param> /// <param name="OnValidateRemoteCertificate">Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication.</param> /// <param name="serverCertificate">The X509Certificate used to authenticate the server.</param> /// <param name="certificatePassword">The password for the private key of the provided server certificate</param> /// <returns>An System.IAsyncResult object that indicates the status of the asynchronous operation.</returns> public async Task StartSslAsServer( string targetHost, System.Security.Authentication.SslProtocols enabledSslProtocols, EncryptionPolicy EncryptionPolicy, bool clientCertificateRequired, LocalCertificateSelectionCallback OnSelectLocalCertificate, bool checkCertificateRevocation, RemoteCertificateValidationCallback OnValidateRemoteCertificate, System.Security.Cryptography.X509Certificates.X509Certificate2 serverCertificate, string certificatePassword = null ) { if (SslStarted) return; await _StartSslAsServer(enabledSslProtocols, EncryptionPolicy, clientCertificateRequired, OnSelectLocalCertificate, checkCertificateRevocation, OnValidateRemoteCertificate, serverCertificate); } /// <summary> /// Called by servers to begin an asynchronous operation to authenticate the server and optionally the client using the specified certificates, requirements and security protocol. /// </summary> /// <param name="targetHost"></param> /// <param name="enabledSslProtocols">The System.Security.Authentication.SslProtocols value that represents the protocol used for authentication</param> /// <param name="EncryptionPolicy">The EncryptionPolicy to use</param> /// <param name="clientCertificateRequired">A System.Boolean value that specifies whether the client must supply a certificate for authentication.</param> /// <param name="OnSelectLocalCertificate">Selects the local Secure Sockets Layer (SSL) certificate used for authentication.</param> /// <param name="checkCertificateRevocation">Indicates if the remote certificate needs to be checked against a official certificate authority</param> /// <param name="OnValidateRemoteCertificate">Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication.</param> /// <param name="serverCertificate">The X509Certificate used to authenticate the server.</param> /// <param name="certificatePassword">The password for the private key of the provided server certificate</param> /// <returns>An System.IAsyncResult object that indicates the status of the asynchronous operation.</returns> async Task _StartSslAsServer(System.Security.Authentication.SslProtocols enabledSslProtocols, EncryptionPolicy EncryptionPolicy, bool clientCertificateRequired, LocalCertificateSelectionCallback OnSelectLocalCertificate, bool checkCertificateRevocation, RemoteCertificateValidationCallback OnValidateRemoteCertificate, System.Security.Cryptography.X509Certificates.X509Certificate2 serverCertificate) { if (SslStarted) return; // set flag SslStarted = true; // prevent timeout SetCurrentStageTimeoutSeconds(50, true); SetActivityTimestamp(); if (SslAdapter == null) { // create asynchronous SslStream adapter SslAdapter = new AsyncSocketHandlerTlsStreamAdapter(Kernel, this); } SslAdapter.Initialize(); // create SslStream SslConversionStream = new SslStream(SslAdapter, true, OnValidateRemoteCertificate, OnSelectLocalCertificate, EncryptionPolicy); // delegate await SslConversionStream.AuthenticateAsServerAsync(serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, null, null); // fire user event HandleTransportSecurityInitiatationCompleted(); } /// <summary> /// Continue without using transport security /// </summary> /// <returns></returns> public async Task StartWithoutSsl() { await Task.Factory.StartNew(() => { }); } /// <summary> /// Starts TLS transport security as client /// </summary> /// <param name="targetHost"></param> /// <returns></returns> public async Task StartSslAsClient(string targetHost = "Self-signed") { if (SslStarted) return; // set flag SslStarted = true; // prevent timeout SetCurrentStageTimeoutSeconds(50, true); SetActivityTimestamp(); // create asynchronous SslStream adapter SslAdapter = new AsyncSocketHandlerTlsStreamAdapter(Kernel, this); // create SslStream SslConversionStream = new SslStream( SslAdapter, true, OnValidateRemoteCertificate ); // start authenticating await SslConversionStream.AuthenticateAsClientAsync(targetHost); // fire user event HandleTransportSecurityInitiatationCompleted(); } public async Task StartSslAsClient( string targetHost, System.Security.Authentication.SslProtocols enabledSslProtocols, EncryptionPolicy EncryptionPolicy, X509CertificateCollection clientCertificates, LocalCertificateSelectionCallback OnSelectLocalCertificate, bool checkCertificateRevocation, RemoteCertificateValidationCallback OnValidateRemoteCertificate ) { if (SslStarted) return; SslStarted = true; SetCurrentStageTimeoutSeconds(50, true); SetActivityTimestamp(); if (SslAdapter == null) { SslAdapter = new AsyncSocketHandlerTlsStreamAdapter(Kernel, this); } SslAdapter.Initialize(); SslConversionStream = new SslStream(SslAdapter, true, OnValidateRemoteCertificate, OnSelectLocalCertificate, EncryptionPolicy); await SslConversionStream.AuthenticateAsClientAsync(targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, null, null); HandleTransportSecurityInitiatationCompleted(); } public void StopSsl() { if (!SslStarted) return; SslStarted = false; if (SslConversionStream != null) { SslConversionStream.Dispose(); SslConversionStream = null; } if (SslAdapter == null) return; SslAdapter.Finalize(rxBuffer); } int receiveCount; async Task PerformReceiveSSL(SocketAsyncEventArgs saea) { var count = receiveCount; var buffer = MemoryManager.TakeBuffer(count); try { int read = 0; read += await SslConversionStream.ReadAsync(buffer, 0, count); rxBuffer.Add(buffer, 0, read); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return count.ToString() + " requested bytes were decrypted and placed into receivebuffer (" + rxBuffer.Count.ToString() + " bytes)"; }); #endif #endregion ------------------------------------------------------------------------------------------------ if (IsCaptured) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(HandleCapturedSocketReceiveSuccess(saea, rxBuffer, txBuffer)) ); } else { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(HandleReceive()) ); } } finally { MemoryManager.ReturnBuffer(buffer); } } async Task PerformSendSSL(SocketAsyncEventArgs saea) { var buffer = MemoryManager.TakeBuffer(MemoryConfiguration.DynamicBufferFragmentSize); try { while (txBuffer.Count > 0) { // remove var read = txBuffer.Remove(buffer, 0, buffer.Length); SocketIO.SetReceiveBufferSize(saea, MemoryConfiguration.ReceiveBufferSize); // send async await SslConversionStream.WriteAsync(buffer, 0, read); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return read.ToString() + " bytes from sendbuffer were encrypted and sent"; }); #endif #endregion ------------------------------------------------------------------------------------------------ } if (IsCaptured) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(HandleCapturedSocketSendSuccess(saea, rxBuffer, txBuffer)) ); } else { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(HandleSend())); } } finally { MemoryManager.ReturnBuffer(buffer); } } System.Security.Cryptography.X509Certificates.X509Certificate2 OnSelectLocalCertificate(object sender, string targetHost, X509CertificateCollection localCertificates, System.Security.Cryptography.X509Certificates.X509Certificate remoteCertificate, string[] acceptableIssuers) { return null; } bool OnValidateRemoteCertificate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "OnValidateRemoteCertificate, returning true"; }); #endif #endregion ------------------------------------------------------------------------------------------------ return true; } System.Security.Cryptography.X509Certificates.X509Certificate2 serverCertificate; static ConcurrentDictionary<string, System.Security.Cryptography.X509Certificates.X509Certificate2> sslCertificates = new ConcurrentDictionary<string, System.Security.Cryptography.X509Certificates.X509Certificate2>(); public static void RemoveCertificateFromCache(string id) { sslCertificates.TryRemove(id, out X509Certificate2 cert); } public static void ClearCertificateMemoryCache(string id) { sslCertificates.Clear(); } public static System.Security.Cryptography.X509Certificates.X509Certificate2 LoadOrCreateServerCertificate( string uniqueName, string certSubjectName, string[] certSubjectAltNames, KeyPurposeID[] usages, string issuerName, string pfxFilePath = null, string certAuthorityCertificatePfxFilePath = null, string pfxFilePassword = null, string certAuthorityCertificatePfxPassword = null, bool autoGenerate = true, bool dontGenerateCACertificate = false ) { lock (sslCertificates) { StringBuilder subjectNames = new StringBuilder(); subjectNames.Append(certSubjectName + "_"); if (certSubjectAltNames != null) { foreach (var s in certSubjectAltNames) subjectNames.Append(s + "_"); } var subjectNamesHash = "h" + GenXdev.Security.MD5.CalculateMD5Hash(subjectNames.ToString()).Substring(0, 9); bool forceRegeneration = false; X509Certificate2 issuerCertificate = LoadOrCreateCertAuthorityCertificate(issuerName, certAuthorityCertificatePfxFilePath, certAuthorityCertificatePfxPassword, autoGenerate && !dontGenerateCACertificate); var id = new StringBuilder(); id.Append(uniqueName); if (issuerCertificate != null) { id.Append("_" + issuerCertificate.GetCertHashString()); } bool found = sslCertificates.TryGetValue(id.ToString(), out X509Certificate2 serverCertificate); if (found) { forceRegeneration = autoGenerate && ( (System.DateTime.UtcNow > serverCertificate.NotAfter) || !serverCertificate.SubjectName.Name.Replace("\"", "").Contains("L=" + subjectNamesHash) ); } if (!found || forceRegeneration) { found = !forceRegeneration && TryLoadCertificateFromFile(id.ToString(), pfxFilePath, pfxFilePassword, out serverCertificate); if (found) { forceRegeneration = autoGenerate && ( (System.DateTime.UtcNow > serverCertificate.NotAfter) || !serverCertificate.SubjectName.Name.Replace("\"", "").Contains("L=" + subjectNamesHash) ); try { GenXdev.Helpers.Pki.WriteCertificateToPemFormat(serverCertificate, Path.ChangeExtension(pfxFilePath, ".public.cer")); } catch { } if (!forceRegeneration) { return serverCertificate; } } if (!found || forceRegeneration) { // re-order and optimize GenXdev.Helpers.Pki.OptimizeAndReorganizeDNSNames(ref certSubjectName, ref certSubjectAltNames); serverCertificate = GenXdev.Helpers.Pki.IssueCertificate( "CN=" + certSubjectName + ", L=" + subjectNamesHash, issuerCertificate, certSubjectAltNames, usages ); sslCertificates.AddOrUpdate(id.ToString(), serverCertificate, (key, oldValue) => serverCertificate); if (!String.IsNullOrWhiteSpace(pfxFilePath)) try { GenXdev.Helpers.Pki.WriteCertificate(serverCertificate, pfxFilePath); GenXdev.Helpers.Pki.WriteCertificateToPemFormat(serverCertificate, Path.ChangeExtension(pfxFilePath, ".public.cer")); } catch { } } return serverCertificate; } return serverCertificate; } } public static bool TryLoadCertificateFromFile( string id, string pfxFilePath, string pfxPassword, out System.Security.Cryptography.X509Certificates.X509Certificate2 serverCertificate ) { serverCertificate = null; if (!String.IsNullOrWhiteSpace(pfxFilePath) && File.Exists(pfxFilePath)) { try { serverCertificate = GenXdev.Helpers.Pki.LoadCertificate(pfxFilePath, pfxPassword); if (System.DateTime.UtcNow <= serverCertificate.NotAfter) { var sc = serverCertificate; sslCertificates.AddOrUpdate(id, serverCertificate, (key, oldValue) => sc); return true; } } catch (Exception e) { serverCertificate = null; GenXdev.Helpers.FileSystem.ForciblyMoveFile(pfxFilePath, pfxFilePath + ".rejected.could.not.open.pfx", false); try { var txtPath = pfxFilePath + ".rejected.could.not.open.txt"; GenXdev.Helpers.FileSystem.ForciblyPrepareTargetFilePath(txtPath); File.WriteAllText(txtPath, e.Message, new UTF8Encoding(false)); } catch { } } } return false; } public static X509Certificate2 LoadOrCreateCertAuthorityCertificate( string certSubjectName, string certAuthorityCertificatePfxFilePath, string certAuthorityCertificatePfxPassword, bool autoGenerate = true ) { X509Certificate2 certAuthorityCertificate = null; lock (sslCertificates) { if (!sslCertificates.TryGetValue(certSubjectName, out certAuthorityCertificate)) { bool forceRegeneration = false; var found = TryLoadCertificateFromFile(certSubjectName, certAuthorityCertificatePfxFilePath, certAuthorityCertificatePfxPassword, out certAuthorityCertificate); if (found) { forceRegeneration = autoGenerate && ( (System.DateTime.UtcNow > certAuthorityCertificate.NotAfter) || (certAuthorityCertificate.SubjectName.Name.Replace("\"", "") != "CN=" + certSubjectName.Trim() + " CA") ); } if (!found || forceRegeneration) { certAuthorityCertificate = GenXdev.Helpers.Pki.CreateCertificateAuthorityCertificate("CN=" + certSubjectName.Trim() + " CA", null, null); sslCertificates.AddOrUpdate(certSubjectName, certAuthorityCertificate, (key, oldValue) => certAuthorityCertificate); if (!String.IsNullOrWhiteSpace(certAuthorityCertificatePfxFilePath)) try { GenXdev.Helpers.Pki.WriteCertificate(certAuthorityCertificate, certAuthorityCertificatePfxFilePath, certAuthorityCertificatePfxPassword); GenXdev.Helpers.Pki.WriteCertificateToPemFormat(certAuthorityCertificate, Path.ChangeExtension(certAuthorityCertificatePfxFilePath, ".cer")); } catch { } } else { try { GenXdev.Helpers.Pki.WriteCertificateToPemFormat(certAuthorityCertificate, Path.ChangeExtension(certAuthorityCertificatePfxFilePath, ".public.cer")); } catch { } } try { // break-point here? you should definitely debug with administrator privileges! X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadWrite); var deleteList = new List<X509Certificate2>(); foreach (var cert in store.Certificates) { if (cert.SubjectName.Name == certAuthorityCertificate.SubjectName.Name) { deleteList.Add(cert); } } foreach (var cert in deleteList) { store.Remove(cert); } X509Certificate2Collection collection = new X509Certificate2Collection(); byte[] encodedCert = certAuthorityCertificate.GetRawCertData(); store.Add(certAuthorityCertificate); store.Close(); } catch { } } } return certAuthorityCertificate; } static SocketHandlerBase() { GenXdev.Helpers.Pki.EnableTlsProtocols(); } #endregion #region Properties public byte[] SslLocalCertificateHash { get { if (SslStarted && (SslConversionStream != null) && (SslConversionStream.LocalCertificate != null)) { //System.Diagnostics.Debug.WriteLine(this.GetType().Name + " -> LOCAL -> " + // GenXdev.Helpers.Hash.FormatBytesAsBase64(GenXdev.Helpers.Hash.GetSha256Bytes(SslConversionStream.LocalCertificate.GetPublicKey()))); return GenXdev.Helpers.Hash.GetSha256Bytes(SslConversionStream.LocalCertificate.GetPublicKey()); } return new byte[0]; } } public byte[] SslRemoteCertificateHash { get { if (SslStarted && (SslConversionStream != null) && (SslConversionStream.RemoteCertificate != null)) { //System.Diagnostics.Debug.WriteLine(this.GetType().Name + " -> REMOTE -> " + // GenXdev.Helpers.Hash.FormatBytesAsBase64(GenXdev.Helpers.Hash.GetSha256Bytes(SslConversionStream.RemoteCertificate.GetPublicKey()))); return GenXdev.Helpers.Hash.GetSha256Bytes(SslConversionStream.RemoteCertificate.GetPublicKey()); } return new byte[0]; } } public bool SslStarted { get; private set; } public bool Idle { get { return (Interlocked.Read(ref _HandlerState) == 0); } //internal protected set //{ // // set state to active // Interlocked.Exchange(ref _HandlerState, 1); //} } public bool Active { get { return (Interlocked.Read(ref _HandlerState) == 1); } } public bool Closing { get { return (Interlocked.Read(ref _HandlerState) >= 2); } } public bool Closed { get { return (Interlocked.Read(ref _HandlerState) == 3); } } // port public int PortNumber { get; private set; } SocketHandlerBase CapturingHandler { get { lock (CaptureRequestQueue) { return _CapturingHandler; } } } internal SocketAsyncEventArgs CapturingSaea { get { lock (CaptureRequestQueue) { return _CapturingHandler.saeaHandler; } } } volatile SocketHandlerBase __ParentHandler; volatile SocketHandlerBase __ChildHandler; internal SocketHandlerBase ParentHandler { get { return __ParentHandler; } private set { __ParentHandler = value; } } internal SocketHandlerBase ChildHandler { get { return __ChildHandler; } private set { __ChildHandler = value; } } public SocketHandlerBase ControllingHandler { get { SocketHandlerBase controller = this; do { var child = controller.ChildHandler; if (child != null) controller = child; } while (controller.ChildHandler != null); return controller; } } /// <summary> /// Indicates whether there is more data ready to be received /// </summary> public bool SocketHasDataAvailable { get { return (SslAdapter != null && SslAdapter.DataAvailable) || (SocketIO != null && SocketIO.SocketHasDataAvailable(saeaHandler)); } } /// <summary> /// Indicates the minimum amount of bytes that can be received instantaniously /// </summary> public int NrOfBytesSocketHasAvailable { get { if (SslAdapter != null) { return SslAdapter.NrOfBytesSocketHasAvailable; } if (SocketIO != null) { return SocketIO.NrOfBytesSocketHasAvailable(saeaHandler); }; return 0; } } /// <summary> /// Indicates whether there is more data in the receivebuffer or ready to be received /// </summary> public bool DataAvailable { get { lock (rxBuffer.SyncRoot) { return (rxBuffer != null && rxBuffer.Count > 0) || (SslAdapter != null && SslAdapter.DataAvailable) || (SocketIO != null && SocketIO.SocketHasDataAvailable(saeaHandler)); } } } public bool IsTimedOut { get { #if (NoSocketTimeouts) return false; #else try { return (!Closing) && (BitConverter.Int64BitsToDouble(Interlocked.Read(ref CurrentStageTimeout)) > 0) && (Timer.Duration - BitConverter.Int64BitsToDouble(Interlocked.Read(ref LastActivityTimeStamp)) > BitConverter.Int64BitsToDouble(Interlocked.Read(ref CurrentStageTimeout))); } catch { return true; } #endif } } public double IdleSeconds { get { #if (NoSocketTimeouts) return 0; #else try { return Timer.Duration - BitConverter.Int64BitsToDouble(Interlocked.Read(ref LastActivityTimeStamp)); } catch { return 0; } #endif } } public string RemoteAddress { get { if (saeaHandler == null || saeaHandler.AcceptSocket == null) return "unknown"; return ((IPEndPoint)saeaHandler.AcceptSocket.RemoteEndPoint).Address.ToString(); } } public int RemotePort { get { if (saeaHandler == null || saeaHandler.AcceptSocket == null) return 0; return ((IPEndPoint)saeaHandler.AcceptSocket.RemoteEndPoint).Port; } } public string RemoteAddressAndPort { get { return RemoteAddress + ":" + RemotePort; } } public string LocalAddress { get { if (saeaHandler == null || saeaHandler.AcceptSocket == null) return "unknown"; return ((IPEndPoint)saeaHandler.AcceptSocket.LocalEndPoint).Address.ToString() + ":" + ((IPEndPoint)saeaHandler.AcceptSocket.LocalEndPoint).Port.ToString(); } } public int LocalPort { get { if (saeaHandler == null || saeaHandler.AcceptSocket == null) return 0; return ((IPEndPoint)saeaHandler.AcceptSocket.LocalEndPoint).Port; } } public string LocalAddressAndPort { get { return LocalAddress + ":" + LocalPort; } } #endregion #region Handler Capturing //public bool isCH = false; void SetCaptured(SocketHandlerBase Registree) { if (IsCaptured) throw new InvalidOperationException(); lock (CaptureRequestQueue) { IsCaptured = true; _CapturingHandler = Registree; SocketIO.Completed -= OnSocketIOCompleted; SocketIO.Completed -= OnCapturedSocketIOCompleted; SocketIO.Completed += OnCapturedSocketIOCompleted; } } SocketHandlerBase ClearCapture() { if (!IsCaptured) throw new InvalidOperationException(); lock (CaptureRequestQueue) { SocketHandlerBase handler = _CapturingHandler; //_CapturingSaea.Handler().isCH = false; IsCaptured = false; _CapturingHandler = null; SocketIO.Completed -= OnSocketIOCompleted; SocketIO.Completed -= OnCapturedSocketIOCompleted; SocketIO.Completed += OnSocketIOCompleted; return handler; } } // enqueues a new capture request if the queue is not full, returns if this is the first request, all as one atomic operation bool TryAddCaptureRequest(SocketHandlerBase Registree, int MaxCaptureRegistrees, out bool IsFirstQueuedCapture) { lock (CaptureRequestQueue) { if ((CaptureRequestQueue.Count >= MaxCaptureRegistrees) && (!Closing)) { IsFirstQueuedCapture = false; return false; } CaptureRequestQueue.Enqueue(Registree); IsFirstQueuedCapture = CaptureRequestQueue.Count == 1; } return true; } // tries to dequeue the next capture request registree as one atomic operation bool TryGetNextCaptureRequest(out SocketHandlerBase Registree) { lock (CaptureRequestQueue) { if (CaptureRequestQueue.Count > 0) { Registree = CaptureRequestQueue.Dequeue(); return true; } } Registree = null; return false; } // returns true if one or more captures are queued protected bool CaptureWaiting() { lock (CaptureRequestQueue) { return (CaptureRequestQueue.Count > 0); } } // tries to register a new capture request and starts it if this handler is IDLE public virtual NextRequestedHandlerAction EnqueueCapture(SocketHandlerBase Registree, int MaxCaptureRegistrees) { /* * Thread/Synchronization/EventChain info: * * When this is the first queued capture and this handler is IDLE, * processing starts right away, if at the same moment * this handler's state becomes closed or closing * processing of this captured event chain, will stop when: * - in async socket operation: the moment the socket get's closed * - starting an async operation * - somewhere in between when both handler's state get checked (see methods region "Other Handler Captured state handling") * - the CloseAndRemoveHandler method calls ReleaseAllCaptures */ // Check HandlerState if (!Closing) { // See if there is enough queue space, if so, add this registree, then check HandlerState again // to prevent race conditions if (TryAddCaptureRequest(Registree, MaxCaptureRegistrees, out bool IsFirstQueuedCapture) && (!Closing)) { // First one in line? if (IsFirstQueuedCapture) { // Start handling if we are in IDLE state TryStartNextCaptureRequest(true, false); } // the flow of the calling chain should be terminated return NextRequestedHandlerAction.Handled; } } // unrequested capture reset return Registree.HandleCapturedSocketReset(false); } // set's and start a new captured state or clears a possible previous one protected bool TryStartNextCaptureRequest(bool OnlyAllowWhenInIdleState = false, bool OnSetIdle = true) { /* * Thread/Synchronization/EventChain info: * * */ // Set handler's state to active if it was IDLE, check current state, continue if all OK if (Interlocked.CompareExchange(ref _HandlerState, 1, 0) < (OnlyAllowWhenInIdleState ? 1 : 2)) { // try to get next enqueued capture registree if (TryGetNextCaptureRequest(out SocketHandlerBase Registree)) { // Set captering handler state to active if it was IDLE, continue if not in closing state if (Interlocked.CompareExchange(ref Registree._HandlerState, 1, 0) < 2) { // make sure not waiting anymore or awaiting polltimer ClearPollIngState(); // Set captured SetCaptured(Registree); // Start handling ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, FireUserEventAndDetermineNextAction(SocketHandlerActions.CaptureAccquired)); // the flow of the calling chain should be terminated here // without it changing it state return true; } else { // close this captering handler Registree.CloseAndReturnHandler(); // try again return TryStartNextCaptureRequest(OnlyAllowWhenInIdleState, OnSetIdle); } } } // the flow of the calling chain should be terminated // after changing the handler's state to IDLE // this will do that if (OnSetIdle) { // set state IDLE (if still active and not marked for termination) otherwise if closing return handler if (TrySetIdle()) { CloseAndReturnHandler(); } } return false; } protected bool TrySetIdle() { return Interlocked.CompareExchange(ref _HandlerState, 0, 1) > 1; } // releases the current capture protected virtual void ReleaseCapture(bool OnClosingSocket = false, bool Requested = false) { /* * Thread/Synchronization/EventChain info: * * This method is called when terminating this handler or when the captured handler * is closed while it has captured this handler. * * Since this method is only executed in the captured event chain of this handler * we don't need to protect access to the CapturedHandler member * */ // check if (!IsCaptured) throw new InvalidOperationException(); // init SocketHandlerActions NextCapturingHandlerAction = SocketHandlerActions.Dispose; // inspect captering handler state switch (Interlocked.Read(ref CapturingHandler._HandlerState)) { // IDLE, should not be possible case 0: throw new InvalidOperationException(); // Active, release was requested, let's determine what it wants next case 1: NextCapturingHandlerAction = FireUserEventAndDetermineNextAction( Requested ? SocketHandlerActions.CaptureReleaseRequest : SocketHandlerActions.CaptureReleasedUnRequested ); break; // Closing, it's socket is timed out, so dispose captering handler case 2: break; // Closed, should normally not be possible case 3: if (!OnClosingSocket) throw new InvalidOperationException(); break; } // reference and clear SocketHandlerBase Registree = ClearCapture(); // continue own event chain if not closing if (!OnClosingSocket) { // let the handler decide what to do next; ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, FireUserEventAndDetermineNextAction(SocketHandlerActions.CaptureReleased)); } // now let the event chain of the now not so much capturing handler continue ThreadPool.QueueUserWorkItem(Registree.PerformNextHandlerActionAsync, NextCapturingHandlerAction); } // stops any captured event chain and removes all capture requests from the queue void ReleaseAllCaptures() { /* * Thread/Synchronization/EventChain info: * * Only called when this handler is closed */ // check if (!Closed) throw new InvalidOperationException(); // remove all enqueued requests while (TryGetNextCaptureRequest(out SocketHandlerBase Registree)) { // inspect registrees handler state switch (Interlocked.Read(ref Registree._HandlerState)) { // IDLE, should not be possible case 0: throw new InvalidOperationException(); // Active, release was unrequested, let it's event chain continue case 1: try { ThreadPool.QueueUserWorkItem(Registree.PerformNextHandlerActionAsync, Registree.TranslateHandlerAction( Registree.HandleCapturedSocketReset(false) ) ); } catch { Registree.CloseAndReturnHandler(); } break; // Closing, it's socket is timed-out, let it's event chain continue case 2: Registree.CloseAndReturnHandler(); break; // Closed, should not be possible // case 3: throw new InvalidOperationException(); } } // clear any current captured state if (IsCaptured) { ReleaseCapture(true); } } #endregion #region Messages protected void ClearAllMessages() { lock (MessageQueue) { MessageQueue.Clear(); } } public void AddMessage(object Message) { if (Closing || Closed) return; if (Message == null) return; lock (MessageQueue) { MessageQueue.Enqueue(Message); } ClearPollIngStateAndContinue(this); } public bool HaveMessages { get { lock (MessageQueue) { return MessageQueue.Count > 0; } } } protected bool TryGetNextMessage(out object Message) { lock (MessageQueue) { if (MessageQueue.Count == 0) { Message = null; return false; } Message = MessageQueue.Dequeue(); return true; } } long connectedTimestamp; public TimeSpan TimeConnected { get { return TimeSpan.FromSeconds(Timer.Duration - BitConverter.Int64BitsToDouble(Interlocked.Read(ref connectedTimestamp))); } } #endregion #region Handler switching public virtual void RegisterHandler(SocketAsyncEventArgs saea, EventHandler<HandlerClosedEventArgs> HandlerClosedCallback = null) { UniqueSocketId = Interlocked.Increment(ref _NextUniqueIdx); saeaHandler = saea; SocketIO.Completed -= OnSocketIOCompleted; SocketIO.Completed -= OnCapturedSocketIOCompleted; SocketIO.Completed += OnSocketIOCompleted; if (HandlerClosedCallback != null) { OnHandlerClosed -= HandlerClosedCallback; OnHandlerClosed += HandlerClosedCallback; } } internal void UnRegisterHandler(SocketAsyncEventArgs saea) { saeaHandler = null; if (saea == null) return; SocketIO.Unregister(saea); SocketIO.Completed -= OnSocketIOCompleted; SocketIO.Completed -= OnCapturedSocketIOCompleted; } // For maintenance static long _startCounter; public void StartHandlingSocket(object state) { try { Interlocked.Increment(ref _startCounter); if (Interlocked.Increment(ref _startCounter) % 10000 == 0) { GC.Collect(); } // state not active any more? if (Interlocked.Read(ref _HandlerState) != 1) { CloseAndReturnHandler(); return; } // init timestamp HandlerStartTimestamp = Timer.Duration; // prevent timeout SetCurrentStageTimeoutSeconds(20, true); SetActivityTimestamp(); // init socket SetNoDelay(true); PortNumber = SocketIO.GetLocalPort(saeaHandler); SocketIO.SetBlocking(saeaHandler, false); SocketIO.SetSendBufferSize(saeaHandler, MemoryConfiguration.SendBufferSize); SocketIO.SetReceiveBufferSize(saeaHandler, MemoryConfiguration.ReceiveBufferSize); PerformFirstHandlerAction(); } catch (Exception e) { OnException(e); this.CloseAndReturnHandler(); } } void PerformFirstHandlerAction() { // start ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, FireUserEventAndDetermineNextAction(SocketHandlerActions.Initialize)); } public NextRequestedHandlerAction TakeOverConrolOfSocket(SocketAsyncEventArgs saea) { // check if ((ChildHandler != null) || (ParentHandler != null)) throw new InvalidOperationException(); // set state to active Interlocked.Exchange(ref _HandlerState, 1); // prevent timeout SetActivityTimestamp(); SetCurrentStageTimeoutSeconds(20); lock (CaptureRequestQueue) { // store new handler ParentHandler = saea.Handler(); ParentHandler.ChildHandler = this; // switch control saea.SetHandler(this); ParentHandler.UnRegisterHandler(saea); RegisterHandler(saea); saeaHandler = saea; SwitchSocketResourcesWithParentHandler(false); } // start handling ThreadPool.QueueUserWorkItem(StartHandlingSocket); // stop the current event chain, but don't change the previous handler's state return NextRequestedHandlerAction.Handled; } void SwitchSocketResourcesWithParentHandler(bool restoring) { // reference SslStream _SslConversionStream = SslConversionStream; AsyncSocketHandlerTlsStreamAdapter _SslAdapter = SslAdapter; DynamicBuffer _rxBuffer = rxBuffer; DynamicBuffer _txBuffer = txBuffer; bool _SslStarted = SslStarted; // switch SslConversionStream = ParentHandler.SslConversionStream; SslAdapter = ParentHandler.SslAdapter; rxBuffer = ParentHandler.rxBuffer; txBuffer = ParentHandler.txBuffer; SslStarted = ParentHandler.SslStarted; ParentHandler.SslConversionStream = _SslConversionStream; ParentHandler.SslAdapter = _SslAdapter; ParentHandler.rxBuffer = _rxBuffer; ParentHandler.txBuffer = _txBuffer; ParentHandler.SslStarted = _SslStarted; if (restoring) { if (_SslAdapter != null) { _SslAdapter.SetHandler(ParentHandler); } } else { if (SslAdapter != null) { SslAdapter.SetHandler(this); } } } internal void ReturnControlOfSocket(SocketAsyncEventArgs saea) { if (ParentHandler != null) { ClearAllMessages(); SocketHandlerBase _ParentHandler; lock (CaptureRequestQueue) { // switch control saea.SetHandler(ParentHandler); UnRegisterHandler(saea); ParentHandler.RegisterHandler(saea); ParentHandler.ChildHandler = null; SwitchSocketResourcesWithParentHandler(true); // reference _ParentHandler = ParentHandler; _ParentHandler.ChildHandler = null; // reset ParentHandler = null; saeaHandler = null; } // start handling ThreadPool.QueueUserWorkItem(_ParentHandler.StartHandlingSocket); CloseAndReturnHandler(); } else { throw new InvalidOperationException(); } } void CloseParentHandler(SocketAsyncEventArgs saea) { // should return control to underlaying handler? if (ParentHandler != null) { // switch control saea.SetHandler(ParentHandler); UnRegisterHandler(saea); ParentHandler.RegisterHandler(saea); ParentHandler.ChildHandler = null; SwitchSocketResourcesWithParentHandler(true); // delegate ParentHandler.CloseAndReturnHandler(); // reset ParentHandler = null; } } #endregion #region Handler Maintenance // called by SocketAsyncEventArgsQueuedPool class // to take care of timed-out sockets // or when it is disposing due to application shutdown public virtual void OnDequeueHandler() { SetCurrentStageTimeoutSeconds(20, true); SetActivityTimestamp(); // set state to active, if it wasn't closed, throw! if (Interlocked.CompareExchange(ref _HandlerState, 1, 3) != 3) { System.Diagnostics.Debugger.Break(); throw new InvalidOperationException(); } // prevent timeout CreateSaea(); } public virtual void OnEnqueueHandler() { } public void Close() { /* * Thread/Synchronization/EventChain info: * * Accessing saea.AcceptSocket is tricky, * the only moments it get's set is: * * - Before the event chain is running on accepting a new socket * - At CloseAndRemoveHandler() when state is Closed * - in OnHandleInitialize() for outgoing sockets, but at this point a timeout could not yet occur, due to the default 0 timeout value * * For these reasons it is safe to access this member when we are in Active state * * The possible race condition mentioned below can only occur once, * and will be catched * */ // is called externally when the handler is timed out // or when the Handler pool is disposing // Set state to "closing" when it is "active", else step into next block if (Interlocked.CompareExchange(ref _HandlerState, 2, 1) != 1) { // Set state to "closing" when it is "idle", if so, step into next block if (Interlocked.CompareExchange(ref _HandlerState, 2, 0) == 0) { // ok state was idle, now we have set it in closing, // since it is not active, we can close it right away CloseAndReturnHandler(); return; } else { // Just to be sure, theoretically a racing condition could occur here // but this one, catches them all if (!Closing) { Close(); return; } // at this point, we notice, it was already closing or closed } } else { // it was "active", now "closing" // close socket try { // we have a socket? SocketIO.Close(ControllingHandler.saeaHandler); } catch { } try { ClearPollIngStateAndContinue(null); } catch { // ignore } } } // closes the socket, cleans-up the instance and let the handler queue return it to the pool void CloseAndReturnHandler() { /* * Thread/Synchronization/EventChain info: * * * */ // set closed, and step in the next block if it wasn't already if (Interlocked.Exchange(ref _HandlerState, 3) != 3) { //if (isCH) System.Diagnostics.Debugger.Break(); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogHandlerFlowMessage(saeaHandler, () => { return "Closing socket"; }); #endif #endregion ------------------------------------------------------------------------------------------------ // reset state // Release all captures if present ReleaseAllCaptures(); // Release all awaiteners out of there wait state lock (SafeBufferAccessLock) { ClearPollIngState(); } SignalAllAwaiteners(); // first close the socket CloseAndDereferenceSocket(); // Reset current stage timeout SetCurrentStageTimeoutSeconds(20); // close underlaying handler if present CloseParentHandler(saeaHandler); lock (SafeBufferAccessLock) { //Reset the handler HandleReset(); } // Reset flag SetActivityTimestamp(); // Clear all queued messages ClearAllMessages(); // Dispose saea DisposeSaea(); // finally, return handler to the queue var callback = OnHandlerClosed; if (callback != null) { callback(this, new HandlerClosedEventArgs(this)); } else { Dispose(true); } } //else if (Closed) System.Diagnostics.Debugger.Break(); } void CloseAndDereferenceSocket() { // do a shutdown before you close the socket try { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Shutting down socket"; }); #endif #endregion ------------------------------------------------------------------------------------------------ //This method closes the socket and releases all resources, both //managed and unmanaged. It internally calls Dispose. try { SocketIO.SetLingerState(saeaHandler, false); } catch { } try { SocketIO.Close(saeaHandler); } catch { } } // throws if socket was already closed #if (Logging) catch (ObjectDisposedException) #else catch (ObjectDisposedException) #endif { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) //Logger.LogHandlerFlowMessage(saeaHandler, () => { return "Closing socket, failed, already closed";}); //Logger.LogException(e, this.GetType().Name + ": Exception occurred"); #endif #endregion ------------------------------------------------------------------------------------------------ } // unknown #if (Logging) catch (SocketException) #else catch (SocketException) #endif { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) //Logger.LogHandlerFlowMessage(saeaHandler, "Shuttingdown socket, failed: " + e.Message); //Logger.LogException(e, this.GetType().Name + ": Exception occurred"); #endif #endregion ------------------------------------------------------------------------------------------------ } if (saeaHandler != null) { saeaHandler.AcceptSocket = null; } // reset flag IsInAsyncCall = false; } #endregion #region Socket I/O handling internal void OnSocketIOCompleted(object sender, SocketAsyncEventArgs saea) { try { // check if (saea != saeaHandler) throw new InvalidOperationException(); if (saea.Handler() != this) throw new InvalidOperationException(); if (IsCaptured) throw new InvalidOperationException(); // reset flag IsInAsyncCall = false; // prevent timeout SetActivityTimestamp(true); // init action SocketHandlerActions Action = SocketHandlerActions.Dispose; // still in active (not idle/closing/closed) state? if (Interlocked.Read(ref _HandlerState) == 1) { var lastOperation = SocketIO.GetLastOperation(saea); // operation successfull? if ((SocketIO.IsConnectionlessSocket(saea) || SocketIO.IsConnected(saea) || (lastOperation == SocketAsyncOperation.Disconnect) ) && (SocketIO.GetSocketError(saea) == SocketError.Success)) { // determine next action switch (lastOperation) { case SocketAsyncOperation.Connect: #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogHandlerFlowMessage(saeaHandler, () => { return "Connected"; }); #endif #endregion ------------------------------------------------------------------------------------------------ Action = SocketHandlerActions.Connect; break; case SocketAsyncOperation.Disconnect: #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogHandlerFlowMessage(saeaHandler, () => { return "Disconnected"; }); #endif #endregion ------------------------------------------------------------------------------------------------ Action = SocketHandlerActions.Disconnect; break; case SocketAsyncOperation.Receive: var bytes = SocketIO.GetBytesTransfered(saeaHandler); if (bytes > 0) { TriggerOnMeasureBytesReceived(Convert.ToUInt64(bytes)); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Received " + bytes.ToString() + " bytes"; }); #endif #endregion ------------------------------------------------------------------------------------------------ Action = SocketHandlerActions.Receive; } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogHandlerFlowMessage(saeaHandler, () => { return "Socket disconnected by peer"; }); #endif #endregion ------------------------------------------------------------------------------------------------ } break; case SocketAsyncOperation.Send: bytes = SocketIO.GetBytesTransfered(saeaHandler); if (bytes > 0) { TriggerOnMeasureBytesSend(Convert.ToUInt64(bytes)); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Sent " + bytes.ToString() + " bytes"; }); #endif #endregion ------------------------------------------------------------------------------------------------ Action = SocketHandlerActions.Send; } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogHandlerFlowMessage(saeaHandler, () => { return "Socket disconnected by peer"; }); #endif #endregion ------------------------------------------------------------------------------------------------ } break; default: #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Unexpected last-operation: " + Enum.GetName(typeof(SocketAsyncOperation), lastOperation); }); #endif #endregion ------------------------------------------------------------------------------------------------ CloseAndReturnHandler(); return; } } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Operation not successfull, last operation: " + Enum.GetName(typeof(SocketAsyncOperation), lastOperation); }); #endif #endregion ------------------------------------------------------------------------------------------------ } } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Handler closed, disposing"; }); #endif #endregion ------------------------------------------------------------------------------------------------ //if (CapturingHandler.Closed) System.Diagnostics.Debugger.Break(); // <-- Action = SocketHandlerActions.Dispose; } // delegate ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, FireUserEventAndDetermineNextAction(Action)); } catch { CloseAndReturnHandler(); } } internal void OnCapturedSocketIOCompleted(object sender, SocketAsyncEventArgs saea) { try { // check if (saea != saeaHandler) throw new InvalidOperationException(); if (saea.Handler() != this) throw new InvalidOperationException(); if (!IsCaptured) throw new InvalidOperationException(); // reset flag IsInAsyncCall = false; // prevent timeout SetActivityTimestamp(true); saea.Handler().SetActivityTimestamp(true); // init action SocketHandlerActions Action = SocketHandlerActions.Dispose; // still in active (not idle/closing/closed) state? if (Interlocked.Read(ref _HandlerState) == 1) { // still in active (not idle/closing/closed) state? if (Interlocked.Read(ref CapturingHandler._HandlerState) == 1) { var lastOperation = SocketIO.GetLastOperation(saea); // operation successfull? if ((SocketIO.IsConnectionlessSocket(saea) || SocketIO.IsConnected(saea) || (lastOperation == SocketAsyncOperation.Disconnect) ) && (SocketIO.GetSocketError(saea) == SocketError.Success)) { // determine next action switch (lastOperation) { case SocketAsyncOperation.Receive: // operation successfull? var bytes = SocketIO.GetBytesTransfered(saea); if (bytes > 0) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saea, () => { return "OnCapturedSocketIOCompleted, Received " + bytes.ToString() + " bytes"; }); #endif #endregion ------------------------------------------------------------------------------------------------ Action = SocketHandlerActions.CapturedReceive; } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogHandlerFlowMessage(saea, () => { return "OnCapturedSocketIOCompleted, socket disconnected by peer"; }); #endif #endregion ------------------------------------------------------------------------------------------------ } break; case SocketAsyncOperation.Send: // operation successfull? bytes = SocketIO.GetBytesTransfered(saea); if (bytes > 0) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) bytes = SocketIO.GetBytesTransfered(saea); Logger.LogSocketFlowMessage(saea, () => { return "OnCapturedSocketIOCompleted, Sent " + bytes.ToString() + " bytes"; }); #endif #endregion ------------------------------------------------------------------------------------------------ Action = SocketHandlerActions.CapturedSend; } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saea, () => { return "OnCapturedSocketIOCompleted, socket disconnected by peer"; }); #endif #endregion ------------------------------------------------------------------------------------------------ } break; case SocketAsyncOperation.Disconnect: #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saea, () => { return "OnCapturedSocketIOCompleted, Disconnected"; }); #endif #endregion ------------------------------------------------------------------------------------------------ Action = SocketHandlerActions.CapturedDisconnect; break; default: #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saea, () => { return "OnCapturedSocketIOCompleted, Unexpected last-operation: " + Enum.GetName(typeof(SocketAsyncOperation), lastOperation); }); #endif #endregion ------------------------------------------------------------------------------------------------ throw new InvalidOperationException(); } } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saea, () => { return "OnCapturedSocketIOCompleted, operation not successfull, last operation: " + Enum.GetName(typeof(SocketAsyncOperation), lastOperation); }); #endif #endregion ------------------------------------------------------------------------------------------------ } } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saea, () => { return "OnCapturedSocketIOCompleted, handler closed, disposing"; }); #endif #endregion ------------------------------------------------------------------------------------------------ //if (CapturingHandler.Closed) System.Diagnostics.Debugger.Break(); // <-- Action = SocketHandlerActions.DisposeCapturingHandler; } } //else if (Closed) System.Diagnostics.Debugger.Break(); // delegate ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, FireUserEventAndDetermineNextAction(Action)); } catch { CloseAndReturnHandler(); } } #endregion #region Polling // Called by another handler who wants to await a signal // from this handler as an alternative to polling // for faster response times public void WakeupOnSignalFrom(SocketHandlerBase supplier, string Signal, HandleSocketBEventArgs e, bool UsePollTimeout) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) Logger.LogSocketFlowMessage( ControllingHandler.saeaHandler, () => { return "Awaiting signal " + Signal + " from " + supplier.GetType().Name; }); #endif #endif #endregion ------------------------------------------------------------------------------------------------ e.NextAction = UsePollTimeout ? NextRequestedHandlerAction.Poll : NextRequestedHandlerAction.WaitForSignal; // register signal waitener lock (supplier.PollingStateLock) { supplier.GetSignalWaitenersHandlers(Signal, this); } // register signal supplier lock (PollingStateLock) { GetSignalSupplierHandlers(Signal, supplier); } } // Signals to other sockethandlers that a condition has occured // on which they can synchronize, as an alternative to polling // for faster response times public void Signal(string Signal) { SafeAccess(() => { SocketHandlerBase[] waiteners; lock (PollingStateLock) { // todo yield return? var list = GetSignalWaitenersHandlers(Signal); if (list == null) return; waiteners = list.ToArray<SocketHandlerBase>(); SignalWaiteners.TryRemove(Signal, out List<SocketHandlerBase> h); } ThreadPool.QueueUserWorkItem((state) => { foreach (var handler in waiteners) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogHandlerFlowMessage(saeaHandler, () => { return "Signalling awaiting " + handler.GetType().Name + ", with signal: " + Signal; }); #endif #endregion ------------------------------------------------------------------------------------------------ handler.ClearPollIngStateAndContinue(Signal); } }); }); } // called when socket closes protected void SignalAllAwaiteners() { // least amount of locking while (true) { // new list var waiteners = new Dictionary<string, List<SocketHandlerBase>>(); // lock lock (PollingStateLock) { // copy list foreach (var entry in SignalWaiteners) { waiteners[entry.Key] = entry.Value; } } // no more awaiteners? then were done if (waiteners.Count == 0) return; // signal all signals foreach (var signal in waiteners.Keys) { Signal(signal); } } } // updates the reference registrations of a signal void RemoveSignalWaitReferences() { List<string> signals = new List<string>(); lock (PollingStateLock) { foreach (var signal in SignalSuppliers.Keys) { signals.Add(signal); } } foreach (string Signal in signals) { // get list of other signals it is waiting for List<SocketHandlerBase> otherHandlers; lock (PollingStateLock) { otherHandlers = GetSignalSupplierHandlers(Signal); SignalSuppliers.TryRemove(Signal, out List<SocketHandlerBase> h); } // found? if (otherHandlers != null) { // process each one foreach (var otherHandler in otherHandlers) { // get list of other handlers who could have provided this signal lock (otherHandler.PollingStateLock) { // find the container holding the reference var otherSignalHandlers = otherHandler.GetSignalWaitenersHandlers(Signal); // found? if (otherSignalHandlers != null) { // lookup the reference var idx = otherSignalHandlers.IndexOf(this); // found? while (idx >= 0) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return "Removing signal awaitener registration on " + otherSignalHandlers.GetType().Name + ", for signal: " + Signal; }); #endif #endif #endregion ------------------------------------------------------------------------------------------------ // remove it otherSignalHandlers.RemoveAt(idx); // container now empty? if (otherSignalHandlers.Count == 0) { // remove signal otherHandler.SignalWaiteners.TryRemove(Signal, out List<SocketHandlerBase> h); break; } idx = otherSignalHandlers.IndexOf(this); } } } } } } } // gets a container with all signals, other handlers are waiting on, optionally pre-initialized List<SocketHandlerBase> GetSignalWaitenersHandlers(string Signal, SocketHandlerBase signalWaitener = null) { // init // list not found, and we should add something? if (!SignalWaiteners.TryGetValue(Signal, out List<SocketHandlerBase> signalHandlers) && signalWaitener != null) { // create a new list signalHandlers = new List<SocketHandlerBase>(); // set it SignalWaiteners[Signal] = signalHandlers; } // add something? if (signalWaitener != null && signalHandlers.IndexOf(signalWaitener) < 0) { // add registree signalHandlers.Add(signalWaitener); } // return container return signalHandlers; } // gets a container with all signals, this handler is currently waiting for, optionally pre-initialized List<SocketHandlerBase> GetSignalSupplierHandlers(string Signal, SocketHandlerBase signalSupplier = null) { // init // list not found, and we should add something? if (!SignalSuppliers.TryGetValue(Signal, out List<SocketHandlerBase> signalHandlers) && signalSupplier != null) { // create a new list signalHandlers = new List<SocketHandlerBase>(); // set it SignalSuppliers[Signal] = signalHandlers; } // add something? if (signalSupplier != null && signalHandlers.IndexOf(signalSupplier) < 0) { // add registree signalHandlers.Add(signalSupplier); } // return container return signalHandlers; } // custom lock object SafeBufferAccessLock = new object(); // provides a context where it is safe to access transmission buffers // from another handler public void SafeAccess(LockCallback callback) { if (Closing || Closed) { throw new Exception("Socket is closed"); } var sessionId = this.UniqueSocketId; lock (SafeBufferAccessLock) { if (Closing || Closed || this.UniqueSocketId != sessionId) { throw new Exception("Socket is closed"); } callback(); } } bool ClearPollIngState() { // try to clear pollingstate from timeractive(1) to disabled(0) if (Interlocked.CompareExchange(ref _PollingState, 0, 1) == 1) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Cleared polling state from timeractive to disabled"; }); #endif #endif #endregion ------------------------------------------------------------------------------------------------ lock (PollingStateLock) { // deactivate timer PollTimer.Change(Timeout.Infinite, Timeout.Infinite); } } else { // try to clear pollingstate from waiting(2) to disabled(0) if (Interlocked.CompareExchange(ref _PollingState, 0, 2) != 2) { // not polling (yet) at this time return false; } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Cleared polling state from waiting to disabled"; }); #endif #endregion ------------------------------------------------------------------------------------------------ } // remove the references RemoveSignalWaitReferences(); return true; } void ClearPollIngStateAndContinue(object state) { if (!ClearPollIngState()) { return; } if (HaveMessages) { if (OnHandleNewMessage != null) { PerformNextHandlerAction(SocketHandlerActions.ProcessReceivedMessage); return; } else { ClearAllMessages(); } } // init next action // still in active (not idle/closing/closed) state? SocketHandlerActions NextAction = Interlocked.Read(ref _HandlerState) == 1 ? NextAction = SocketHandlerActions.Poll : SocketHandlerActions.Dispose; PerformNextHandlerAction(FireUserEventAndDetermineNextAction(NextAction)); } private long _PollIntervalMs = 500; protected void SetPollIntervalMs(long NewInterval) { Interlocked.Exchange(ref _PollIntervalMs, NewInterval); } #endregion #region Handling void PerformNextHandlerActionAsync(object NextAction) { PerformNextHandlerAction((SocketHandlerActions)NextAction); } void PerformNextHandlerAction(SocketHandlerActions NextAction) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) if ((NextAction != SocketHandlerActions.Poll) && (NextAction != SocketHandlerActions.Handled)) { Logger.LogSocketFlowMessage(saeaHandler, () => { return "Starting operation: " + Enum.GetName(typeof(SocketHandlerActions), NextAction); }); } #endif #endregion ------------------------------------------------------------------------------------------------ if (Closing) { CloseAndReturnHandler(); return; } var HandledAsync = true; try { switch (NextAction) { case SocketHandlerActions.None: break; case SocketHandlerActions.Handled: // clean-up handler if closing if (Interlocked.Read(ref _HandlerState) == 2) { CloseAndReturnHandler(); } break; case SocketHandlerActions.SetIdle: // try to start next capture, or set state IDLE TryStartNextCaptureRequest(); break; case SocketHandlerActions.Connect: // remember connection time Interlocked.Exchange(ref connectedTimestamp, BitConverter.DoubleToInt64Bits(Timer.Duration)); // connect saeaHandler.SetBuffer(0, 0); HandledAsync = (IsInAsyncCall = SocketIO.ConnectAsync(saeaHandler)); break; case SocketHandlerActions.AsyncAction: Task.Factory.StartNew(async delegate { try { await HandleAsyncAction(); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return; case SocketHandlerActions.Send: case SocketHandlerActions.CapturedSend: SetActivityTimestamp(true); if (SslStarted) { Task.Factory.StartNew(async delegate { try { await PerformSendSSL(saeaHandler); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return; } SocketIO.SetReceiveBufferSize(saeaHandler, MemoryConfiguration.ReceiveBufferSize); txBuffer.FillAndSetSendBuffer(saeaHandler, MemoryConfiguration.SendBufferSize, false); HandledAsync = (IsInAsyncCall = SocketIO.SendAsync(saeaHandler)); break; case SocketHandlerActions.Receive: case SocketHandlerActions.CapturedReceive: SetActivityTimestamp(true); if (SslStarted) { var t = Task.Factory.StartNew(async delegate { try { await PerformReceiveSSL(saeaHandler); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return; } if (saeaHandler.Buffer == null) { SetReceiveBuffer(MemoryConfiguration.ReceiveBufferSize); } HandledAsync = (IsInAsyncCall = SocketIO.ReceiveAsync(saeaHandler)); break; case SocketHandlerActions.StopTransportSecurity: ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(HandleStopTransportSecurity())); break; case SocketHandlerActions.Disconnect: case SocketHandlerActions.CapturedDisconnect: saeaHandler.SetBuffer(0, 0); SocketIO.Shutdown(saeaHandler, SocketShutdown.Receive); SocketIO.SetLingerTime(saeaHandler, 5000); SocketIO.SetLingerState(saeaHandler, true); SetActivityTimestamp(); SetCurrentStageTimeoutSeconds(5, false); HandledAsync = (IsInAsyncCall = SocketIO.DisconnectAsync(saeaHandler)); break; case SocketHandlerActions.Poll: if (HaveMessages) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, SocketHandlerActions.ProcessReceivedMessage); } else { // start timer lock (PollingStateLock) { PollTimer.Change(Convert.ToInt32(Interlocked.Read(ref _PollIntervalMs)), Timeout.Infinite); } // failed, try to set polling state from disabled to timer if (Interlocked.CompareExchange(ref _PollingState, 1, 0) != 0) { throw new InvalidOperationException(); } else { #if (LogPolling) #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Setting polling state from disabled to timer"; }); #endif #endregion ------------------------------------------------------------------------------------------------ #endif } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Starting polling timer"; }); #endif #endif #endregion ------------------------------------------------------------------------------------------------ } break; case SocketHandlerActions.WaitForSignal: if (SignalSuppliers.Count == 0) { throw new Exception("No signals registered to wait for!"); } // try to set polling state from disabled to wait if (Interlocked.CompareExchange(ref _PollingState, 2, 0) != 0) { throw new InvalidOperationException(); } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (LogPolling) #if (Logging) Logger.LogHandlerFlowMessage(saeaHandler, () => { return "Setting polling state from disabled to wait"; }); #endif #endif #endregion ------------------------------------------------------------------------------------------------ } break; case SocketHandlerActions.WaitForMessage: if (HaveMessages) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, SocketHandlerActions.ProcessReceivedMessage); return; } // failed, try to set polling state from disabled to wait if (Interlocked.CompareExchange(ref _PollingState, 2, 0) != 0) { throw new InvalidOperationException(); } else { #region ---------------------------------------------------------------------------------------------[LOG]- #if (LogPolling) #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Setting polling state from disabled to wait"; }); #endif #endif #endregion ------------------------------------------------------------------------------------------------ } break; case SocketHandlerActions.ProcessReceivedMessage: object message; lock (MessageQueue) { message = MessageQueue.Dequeue(); } ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(HandleOnNewMessage(message))); break; case SocketHandlerActions.Dispose: CloseAndReturnHandler(); break; case SocketHandlerActions.ReleaseControl: ReturnControlOfSocket(saeaHandler); break; case SocketHandlerActions.CaptureReleaseRequest: ReleaseCapture(false, true); break; case SocketHandlerActions.CaptureReleasedUnRequested: ReleaseCapture(false, false); break; case SocketHandlerActions.DisposeCapturingHandler: CapturingHandler.Close(); ReleaseCapture(); break; default: throw new InvalidOperationException(); } if (Closing) { CloseAndReturnHandler(); } if (!HandledAsync) { if (IsCaptured) { OnCapturedSocketIOCompleted(null, saeaHandler); } else { OnSocketIOCompleted(null, saeaHandler); } } } catch (Exception e) { OnException(e); CloseAndReturnHandler(); } } SocketHandlerActions TranslateHandlerAction(NextRequestedHandlerAction NextAction) { switch (NextAction) { case NextRequestedHandlerAction.Connect: return SocketHandlerActions.Connect; case NextRequestedHandlerAction.AsyncAction: return SocketHandlerActions.AsyncAction; case NextRequestedHandlerAction.Receive: return SocketHandlerActions.Receive; case NextRequestedHandlerAction.Send: return SocketHandlerActions.Send; case NextRequestedHandlerAction.StopTransportSecurity: return SocketHandlerActions.StopTransportSecurity; case NextRequestedHandlerAction.Disconnect: return SocketHandlerActions.Disconnect; case NextRequestedHandlerAction.Poll: return SocketHandlerActions.Poll; case NextRequestedHandlerAction.WaitForSignal: return SocketHandlerActions.WaitForSignal; case NextRequestedHandlerAction.WaitForMessage: return SocketHandlerActions.WaitForMessage; case NextRequestedHandlerAction.Dispose: return SocketHandlerActions.Dispose; case NextRequestedHandlerAction.SetIdle: return SocketHandlerActions.SetIdle; case NextRequestedHandlerAction.Handled: return SocketHandlerActions.Handled; case NextRequestedHandlerAction.ReleaseControl: return SocketHandlerActions.ReleaseControl; default: throw new NotImplementedException(); } } SocketHandlerActions TranslateHandlerAction(NextRequestedCapturedHandlerAction NextAction) { switch (NextAction) { case NextRequestedCapturedHandlerAction.Handled: return SocketHandlerActions.Handled; case NextRequestedCapturedHandlerAction.Receive: return SocketHandlerActions.CapturedReceive; case NextRequestedCapturedHandlerAction.Send: return SocketHandlerActions.CapturedSend; case NextRequestedCapturedHandlerAction.Disconnect: return SocketHandlerActions.CapturedDisconnect; case NextRequestedCapturedHandlerAction.DisposeCapturedHandler: return SocketHandlerActions.Dispose; case NextRequestedCapturedHandlerAction.DisposeCapturingHandler: return SocketHandlerActions.DisposeCapturingHandler; case NextRequestedCapturedHandlerAction.Release: return SocketHandlerActions.CaptureReleaseRequest; default: throw new NotImplementedException(); } } internal SocketHandlerActions FireUserEventAndDetermineNextAction(SocketHandlerActions Action) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) if (Action != SocketHandlerActions.Poll) { Logger.LogSocketFlowMessage(saeaHandler, () => { return "Handling action: " + Enum.GetName(typeof(SocketHandlerActions), Action); }); } #endif #endregion ------------------------------------------------------------------------------------------------ try { switch (Action) { case SocketHandlerActions.Initialize: return TranslateHandlerAction(HandleInitialize()); case SocketHandlerActions.Connect: return TranslateHandlerAction(HandleConnect()); case SocketHandlerActions.AsyncAction: throw new InvalidOperationException(); case SocketHandlerActions.Send: if (SslStarted) { SslAdapter.HandleSend(); return SocketHandlerActions.Handled; } return TranslateHandlerAction(HandleSend()); case SocketHandlerActions.Receive: if (SslStarted) { SslAdapter.HandleReceive(); return SocketHandlerActions.Handled; } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Received (no ssl) " + SocketIO.GetBytesTransfered(saeaHandler).ToString() + " bytes into receivebuffer"; }); #endif #endregion ------------------------------------------------------------------------------------------------ SocketIO.GetReceivedData(saeaHandler, rxBuffer); return TranslateHandlerAction(HandleReceive()); case SocketHandlerActions.StopTransportSecurity: throw new InvalidOperationException(); case SocketHandlerActions.Disconnect: return TranslateHandlerAction(HandleDisconnect()); case SocketHandlerActions.Poll: return TranslateHandlerAction(HandlePoll()); case SocketHandlerActions.WaitForSignal: throw new InvalidOperationException(); case SocketHandlerActions.WaitForMessage: throw new InvalidOperationException(); case SocketHandlerActions.ProcessReceivedMessage: object message; lock (MessageQueue) { message = MessageQueue.Dequeue(); } return TranslateHandlerAction(HandleOnNewMessage(message)); case SocketHandlerActions.ReleaseControl: return SocketHandlerActions.Initialize; case SocketHandlerActions.CaptureReleased: return TranslateHandlerAction(HandleCaptureRelease()); case SocketHandlerActions.CaptureAccquired: return TranslateHandlerAction(CapturingHandler.HandleCapturedSocketInitialize(saeaHandler, rxBuffer, txBuffer)); case SocketHandlerActions.CaptureReleaseRequest: return TranslateHandlerAction(CapturingHandler.HandleCapturedSocketReset(true)); case SocketHandlerActions.CaptureReleasedUnRequested: return TranslateHandlerAction(CapturingHandler.HandleCapturedSocketReset(false)); case SocketHandlerActions.CapturedSend: if (SslStarted) { SslAdapter.HandleSend(); return SocketHandlerActions.Handled; } return TranslateHandlerAction(CapturingHandler.HandleCapturedSocketSendSuccess(saeaHandler, rxBuffer, txBuffer)); case SocketHandlerActions.CapturedDisconnect: return TranslateHandlerAction(CapturingHandler.HandleCapturedSocketDisconnectSuccess(saeaHandler)); case SocketHandlerActions.CapturedReceive: if (SslStarted) { SslAdapter.HandleReceive(); return SocketHandlerActions.Handled; } SocketIO.GetReceivedData(saeaHandler, rxBuffer); return TranslateHandlerAction(CapturingHandler.HandleCapturedSocketReceiveSuccess(saeaHandler, rxBuffer, txBuffer)); default: return Action; } } #region Exception Handling #if (Logging) catch (Exception e) #else catch (Exception e) #endif { _HandleException(e); throw; } #endregion } #endregion #region Handling Events protected internal event EventHandler<HandleSocketBEventArgs> OnHandleInitialize; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketBEventArgs, Task> OnHandleInitializeAsync; NextRequestedHandlerAction HandleInitialize() { var handler = OnHandleInitialize; var asyncHandler = OnHandleInitializeAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandleInitialize is not handled, you need to assign the normal or async eventhandler"); } if (_args_Uncaptured == null) { _args_Uncaptured = new HandleSocketBEventArgs(rxBuffer, txBuffer); } else { _args_Uncaptured.RxBuffer = rxBuffer; _args_Uncaptured.TxBuffer = txBuffer; _args_Uncaptured.Count = null; _args_Uncaptured.NextAction = NextRequestedHandlerAction.Dispose; } if (handler != null) { handler(this, _args_Uncaptured); CheckArgumentsCountProperty(_args_Uncaptured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) #else if (_args_Uncaptured.NextAction != NextRequestedHandlerAction.Poll) #endif Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleInitialize -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ return _args_Uncaptured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Uncaptured); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_Uncaptured); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) #else if (_args_Uncaptured.NextAction != NextRequestedHandlerAction.Poll) #endif Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleInitialize -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Uncaptured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } protected internal event EventHandler<HandleSocketBEventArgs> OnHandleCaptureRelease; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketBEventArgs, Task> OnHandleCaptureReleaseAsync; NextRequestedHandlerAction HandleCaptureRelease() { var handler = OnHandleCaptureRelease; var asyncHandler = OnHandleCaptureReleaseAsync; if (handler == null && asyncHandler == null) { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCaptureRelease -> [DEFAULT] DISPOSE (no handler)"; }); #endif #endregion ------------------------------------------------------------------------------------------------ return NextRequestedHandlerAction.Dispose; } if (_args_Uncaptured == null) { _args_Uncaptured = new HandleSocketBEventArgs(rxBuffer, txBuffer); } else { _args_Uncaptured.RxBuffer = rxBuffer; _args_Uncaptured.TxBuffer = txBuffer; _args_Uncaptured.Count = null; _args_Uncaptured.NextAction = NextRequestedHandlerAction.Dispose; } if (handler != null) { handler(this, _args_Uncaptured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) #else if (_args_Uncaptured.NextAction != NextRequestedHandlerAction.Poll) #endif Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCaptureRelease -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); return _args_Uncaptured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Uncaptured); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_Uncaptured); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) #else if (_args_Uncaptured.NextAction != NextRequestedHandlerAction.Poll) #endif Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandlCaptureRelease -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Uncaptured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } protected internal event EventHandler<HandleSocketBEventArgs> OnHandlePoll; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketBEventArgs, Task> OnHandlePollAsync; NextRequestedHandlerAction HandlePoll() { var handler = OnHandlePoll; var asyncHandler = OnHandlePollAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandlePoll is not handled, you need to assign the eventhandler"); } if (_args_Uncaptured == null) { _args_Uncaptured = new HandleSocketBEventArgs(rxBuffer, txBuffer); } else { _args_Uncaptured.RxBuffer = rxBuffer; _args_Uncaptured.TxBuffer = txBuffer; _args_Uncaptured.Count = null; _args_Uncaptured.NextAction = NextRequestedHandlerAction.Dispose; } if (handler != null) { handler(this, _args_Uncaptured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) #else if (_args_Uncaptured.NextAction != NextRequestedHandlerAction.Poll) #endif Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandlePoll -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); return _args_Uncaptured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Uncaptured); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_Uncaptured); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) #else if (_args_Uncaptured.NextAction != NextRequestedHandlerAction.Poll) #endif Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandlePoll -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Uncaptured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } protected internal event EventHandler<HandleSocketMessageEventArgs> OnHandleNewMessage; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketBEventArgs, Task> OnHandleNewMessageAsync; NextRequestedHandlerAction HandleOnNewMessage(object Message) { var handler = OnHandleNewMessage; var asyncHandler = OnHandleNewMessageAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandleNewMessage is not handled, you need to assign the eventhandler"); } if (_args_OnNewMessage == null) { _args_OnNewMessage = new HandleSocketMessageEventArgs(rxBuffer, txBuffer, Message); } else { _args_OnNewMessage.Message = Message; _args_OnNewMessage.RxBuffer = rxBuffer; _args_OnNewMessage.TxBuffer = txBuffer; _args_OnNewMessage.Count = null; _args_OnNewMessage.NextAction = NextRequestedHandlerAction.Dispose; } if (handler != null) { handler(this, _args_OnNewMessage); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) #else if (_args_OnNewMessage.NextAction != NextRequestedHandlerAction.Poll) #endif Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleOnNewMessage -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_OnNewMessage.NextAction) + (_args_OnNewMessage.Count.HasValue ? " (Count = " + _args_OnNewMessage.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_OnNewMessage); return _args_OnNewMessage.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_OnNewMessage); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_OnNewMessage); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) #else if (_args_OnNewMessage.NextAction != NextRequestedHandlerAction.Poll) #endif Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleOnNewMessage -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_OnNewMessage.NextAction) + (_args_OnNewMessage.Count.HasValue ? " (Count = " + _args_OnNewMessage.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_OnNewMessage); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_OnNewMessage.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } protected internal event EventHandler<HandleSocketBEventArgs> OnHandleConnect; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketBEventArgs, Task> OnHandleConnectAsync; NextRequestedHandlerAction HandleConnect() { var handler = OnHandleConnect; var asyncHandler = OnHandleConnectAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandleConnect is not handled, you need to assign the eventhandler"); } if (_args_Uncaptured == null) { _args_Uncaptured = new HandleSocketBEventArgs(rxBuffer, txBuffer); } else { _args_Uncaptured.RxBuffer = rxBuffer; _args_Uncaptured.TxBuffer = txBuffer; _args_Uncaptured.Count = null; _args_Uncaptured.NextAction = NextRequestedHandlerAction.Dispose; } if (handler != null) { handler(this, _args_Uncaptured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleConnect -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); return _args_Uncaptured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Uncaptured); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_Uncaptured); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleConnect -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Uncaptured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } protected internal event EventHandler<HandleSocketEventArgs> OnHandleDisconnect; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketEventArgs, Task> OnHandleDisconnectAsync; NextRequestedHandlerAction HandleDisconnect() { var handler = OnHandleDisconnect; var asyncHandler = OnHandleDisconnectAsync; if (handler == null && asyncHandler == null) { return NextRequestedHandlerAction.Dispose; } if (_args_HandleDisconnect == null) { _args_HandleDisconnect = new HandleSocketEventArgs(); } else { _args_HandleDisconnect.NextAction = NextRequestedHandlerAction.Dispose; } if (handler != null) { handler(this, _args_HandleDisconnect); return _args_HandleDisconnect.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_HandleDisconnect); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleDisconnect -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_HandleDisconnect.NextAction); }); #endif #endregion ------------------------------------------------------------------------------------------------ ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Uncaptured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketBEventArgs, Task> OnHandleAsyncAction; async Task HandleAsyncAction() { var handler = OnHandleAsyncAction; if (handler != null) { if (_args_Uncaptured == null) { _args_Uncaptured = new HandleSocketBEventArgs(rxBuffer, txBuffer); } else { _args_Uncaptured.RxBuffer = rxBuffer; _args_Uncaptured.TxBuffer = txBuffer; _args_Uncaptured.Count = null; _args_Uncaptured.NextAction = NextRequestedHandlerAction.Dispose; } bool sslStarted = this.SslStarted; await handler(this, _args_Uncaptured); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_Uncaptured); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleAsyncAction -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Uncaptured.NextAction)); return; } throw new InvalidOperationException("HandleAsyncAction is not handled"); } // todo cleanup /// <summary> /// allows descendent classes to override default nextaction after Transportsecurity is set by their descendents /// </summary> protected virtual void AfterHandleStartTransportSecurity(object sender, HandleSocketBEventArgs e) { } protected internal event EventHandler<HandleSocketBEventArgs> OnHandleReceive; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketBEventArgs, Task> OnHandleReceiveAsync; NextRequestedHandlerAction HandleReceive() { var handler = OnHandleReceive; var asyncHandler = OnHandleReceiveAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandleReceive is not handled, you need to assign the eventhandler"); } if (_args_Uncaptured == null) { _args_Uncaptured = new HandleSocketBEventArgs(rxBuffer, txBuffer); } else { _args_Uncaptured.RxBuffer = rxBuffer; _args_Uncaptured.TxBuffer = txBuffer; _args_Uncaptured.Count = null; _args_Uncaptured.NextAction = NextRequestedHandlerAction.Dispose; } if (handler != null) { handler(this, _args_Uncaptured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleReceive -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); return _args_Uncaptured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Uncaptured); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_Uncaptured); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleReceive -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Uncaptured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } protected internal event EventHandler<HandleSocketBEventArgs> OnHandleSend; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketBEventArgs, Task> OnHandleSendAsync; NextRequestedHandlerAction HandleSend() { var handler = OnHandleSend; var asyncHandler = OnHandleSendAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandleSend is not handled, you need to assign the eventhandler"); } if (handler != null) { if (_args_Uncaptured == null) { _args_Uncaptured = new HandleSocketBEventArgs(rxBuffer, txBuffer); } else { _args_Uncaptured.RxBuffer = rxBuffer; _args_Uncaptured.TxBuffer = txBuffer; _args_Uncaptured.Count = null; _args_Uncaptured.NextAction = NextRequestedHandlerAction.Dispose; } handler(this, _args_Uncaptured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleSend -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); return _args_Uncaptured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Uncaptured); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_Uncaptured); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleSend -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Uncaptured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } protected internal event EventHandler<HandleSocketBEventArgs> OnHandleStopTransportSecurity; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleSocketBEventArgs, Task> OnHandleStopTransportSecurityAsync; NextRequestedHandlerAction HandleStopTransportSecurity() { var handler = OnHandleStopTransportSecurity; var asyncHandler = OnHandleStopTransportSecurityAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandleStopTransportSecurity is not handled, you need to assign the eventhandler"); } StopSsl(); if (_args_Uncaptured == null) { _args_Uncaptured = new HandleSocketBEventArgs(rxBuffer, txBuffer); } else { _args_Uncaptured.RxBuffer = rxBuffer; _args_Uncaptured.TxBuffer = txBuffer; _args_Uncaptured.Count = null; _args_Uncaptured.NextAction = NextRequestedHandlerAction.Dispose; } if (handler != null) { handler(this, _args_Uncaptured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleStopTransportSecurity -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); return _args_Uncaptured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Uncaptured); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_Uncaptured); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleStopTransportSecurity -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Uncaptured.NextAction) + (_args_Uncaptured.Count.HasValue ? " (Count = " + _args_Uncaptured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Uncaptured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Uncaptured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } protected internal event EventHandler<OnHandleExceptionEventArgs> OnHandleException; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] void OnException(Exception e) { try { var handler = OnHandleException; if (handler != null) { if (_args_OnHandleException == null) { _args_OnHandleException = new OnHandleExceptionEventArgs(e); } else { _args_OnHandleException.Exception = e; } handler(this, _args_OnHandleException); } } catch { } } protected internal event EventHandler OnHandleReset; void HandleReset() { StopSsl(); rxBuffer.Reset(); txBuffer.Reset(); SignalWaiteners.Clear(); SignalSuppliers.Clear(); var handler = OnHandleReset; if (handler != null) { handler(this, EventArgs.Empty); } } protected internal event EventHandler<HandleCapturedSocketBEventArg> OnHandleCapturedSocketInitialize; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleCapturedSocketBEventArg, Task> OnHandleCapturedSocketInitializeAsync; NextRequestedCapturedHandlerAction HandleCapturedSocketInitialize(SocketAsyncEventArgs saeaCapture, DynamicBuffer rxBuffer, DynamicBuffer txBuffer) { SetActivityTimestamp(); var handler = OnHandleCapturedSocketInitialize; var asyncHandler = OnHandleCapturedSocketInitializeAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandleCapturedSocketInitialize is not handled, you need to assign the eventhandler"); } if (_args_Captured == null) { _args_Captured = new HandleCapturedSocketBEventArg(saeaCapture, saeaCapture.Handler().ControllingHandler.SocketHasDataAvailable, rxBuffer, txBuffer); } else { _args_Captured.Count = null; _args_Captured.NextAction = NextRequestedCapturedHandlerAction.Release; _args_Captured.RxBuffer = rxBuffer; _args_Captured.TxBuffer = txBuffer; _args_Captured.saeaCapture = saeaCapture; _args_Captured.socketHasDataAvailable = saeaCapture.Handler().ControllingHandler.SocketHasDataAvailable; } if (handler != null) { handler(this, _args_Captured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCapturedSocketInitialize -> " + Enum.GetName(typeof(NextRequestedCapturedHandlerAction), _args_Captured.NextAction) + (_args_Captured.Count.HasValue ? " (Count = " + _args_Captured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Captured); return _args_Captured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Captured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCapturedSocketInitialize -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Captured.NextAction) + (_args_Captured.Count.HasValue ? " (Count = " + _args_Captured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Captured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Captured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedCapturedHandlerAction.Handled; } protected internal event EventHandler<HandleCapturedSocketBEventArg> OnHandleCapturedSocketReceiveSuccess; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleCapturedSocketBEventArg, Task> OnHandleCapturedSocketReceiveSuccessAsync; NextRequestedCapturedHandlerAction HandleCapturedSocketReceiveSuccess(SocketAsyncEventArgs saeaCapture, DynamicBuffer rxBuffer, DynamicBuffer txBuffer) { var handler = OnHandleCapturedSocketReceiveSuccess; var asyncHandler = OnHandleCapturedSocketReceiveSuccessAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandleCapturedSocketReceiveSuccess is not handled, you need to assign the eventhandler"); } if (_args_Captured == null) { _args_Captured = new HandleCapturedSocketBEventArg(saeaCapture, saeaCapture.Handler().ControllingHandler.SocketHasDataAvailable, rxBuffer, txBuffer); } else { _args_Captured.Count = null; _args_Captured.NextAction = NextRequestedCapturedHandlerAction.Release; _args_Captured.RxBuffer = rxBuffer; _args_Captured.TxBuffer = txBuffer; _args_Captured.saeaCapture = saeaCapture; _args_Captured.socketHasDataAvailable = saeaCapture.Handler().ControllingHandler.SocketHasDataAvailable; } if (handler != null) { handler(this, _args_Captured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCapturedSocketReceiveSuccess-> " + Enum.GetName(typeof(NextRequestedCapturedHandlerAction), _args_Captured.NextAction) + (_args_Captured.Count.HasValue ? " (Count = " + _args_Captured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Captured); return _args_Captured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Captured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCapturedSocketReceiveSuccess -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Captured.NextAction) + (_args_Captured.Count.HasValue ? " (Count = " + _args_Captured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Captured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Captured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedCapturedHandlerAction.Handled; } protected internal event EventHandler<HandleCapturedSocketEventArgs> OnHandleCapturedSocketDisconnectSuccess; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleCapturedSocketEventArgs, Task> OnHandleCapturedSocketDisconnectSuccessAsync; NextRequestedCapturedHandlerAction HandleCapturedSocketDisconnectSuccess(SocketAsyncEventArgs saeaCapture) { var handler = OnHandleCapturedSocketDisconnectSuccess; var asyncHandler = OnHandleCapturedSocketDisconnectSuccessAsync; if (handler == null && asyncHandler == null) { return NextRequestedCapturedHandlerAction.DisposeCapturingHandler; } if (_args_CapturedDisconnect == null) { _args_CapturedDisconnect = new HandleCapturedSocketEventArgs(saeaCapture, false); } else { _args_CapturedDisconnect.NextAction = NextRequestedCapturedHandlerAction.Release; _args_CapturedDisconnect.saeaCapture = saeaCapture; _args_CapturedDisconnect.socketHasDataAvailable = false; } if (handler != null) { handler(this, _args_CapturedDisconnect); return _args_CapturedDisconnect.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_CapturedDisconnect); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCapturedSocketDisconnectSuccess"; }); #endif #endregion ------------------------------------------------------------------------------------------------ ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_CapturedDisconnect.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedCapturedHandlerAction.Handled; } protected internal event EventHandler<HandleCapturedSocketBEventArg> OnHandleCapturedSocketSendSuccess; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleCapturedSocketBEventArg, Task> OnHandleCapturedSocketSendSuccessAsync; NextRequestedCapturedHandlerAction HandleCapturedSocketSendSuccess(SocketAsyncEventArgs saeaCapture, DynamicBuffer rxBuffer, DynamicBuffer txBuffer) { var handler = OnHandleCapturedSocketSendSuccess; var asyncHandler = OnHandleCapturedSocketSendSuccessAsync; if (handler == null && asyncHandler == null) { throw new InvalidOperationException("OnHandleCapturedSocketSendSuccess is not handled, you need to assign the eventhandler"); } if (_args_Captured == null) { _args_Captured = new HandleCapturedSocketBEventArg(saeaCapture, saeaCapture.Handler().ControllingHandler.SocketHasDataAvailable, rxBuffer, txBuffer); } else { _args_Captured.Count = null; _args_Captured.NextAction = NextRequestedCapturedHandlerAction.Release; _args_Captured.RxBuffer = rxBuffer; _args_Captured.TxBuffer = txBuffer; _args_Captured.saeaCapture = saeaCapture; _args_Captured.socketHasDataAvailable = saeaCapture.Handler().ControllingHandler.SocketHasDataAvailable; } if (handler != null) { handler(this, _args_Captured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCapturedSocketSendSuccess-> " + Enum.GetName(typeof(NextRequestedCapturedHandlerAction), _args_Captured.NextAction) + (_args_Captured.Count.HasValue ? " (Count = " + _args_Captured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Captured); return _args_Captured.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_Captured); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCapturedSocketSendSuccess -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_Captured.NextAction) + (_args_Captured.Count.HasValue ? " (Count = " + _args_Captured.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_Captured); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_Captured.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedCapturedHandlerAction.Handled; } protected internal event EventHandler<HandleCapturedSocketResetEventArgs> OnHandleCapturedSocketReset; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleCapturedSocketResetEventArgs, Task> OnHandleCapturedSocketResetAsync; internal NextRequestedHandlerAction HandleCapturedSocketReset(bool ResetWasRequested) { var handler = OnHandleCapturedSocketReset; var asyncHandler = OnHandleCapturedSocketResetAsync; if (handler == null && asyncHandler == null) { return NextRequestedHandlerAction.Dispose; } if (_args_HandleCapturedSocketReset == null) { _args_HandleCapturedSocketReset = new HandleCapturedSocketResetEventArgs(ResetWasRequested, rxBuffer, txBuffer); } else { _args_HandleCapturedSocketReset.Count = null; _args_HandleCapturedSocketReset.NextAction = NextRequestedHandlerAction.Dispose; _args_HandleCapturedSocketReset.RxBuffer = rxBuffer; _args_HandleCapturedSocketReset.TxBuffer = txBuffer; _args_HandleCapturedSocketReset.ResetWasRequested = ResetWasRequested; } if (handler != null) { handler(this, _args_HandleCapturedSocketReset); CheckArgumentsCountProperty(_args_HandleCapturedSocketReset); #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCapturedSocketReset -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_HandleCapturedSocketReset.NextAction) + (_args_HandleCapturedSocketReset.Count.HasValue ? " (Count = " + _args_HandleCapturedSocketReset.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ return _args_HandleCapturedSocketReset.NextAction; } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; if (Closing) { ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, NextRequestedHandlerAction.Dispose); return; } await asyncHandler(this, _args_HandleCapturedSocketReset); if (SslStarted && (sslStarted != SslStarted)) { AfterHandleStartTransportSecurity(this, _args_HandleCapturedSocketReset); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) #if (LogPolling) #else if (_args_Uncaptured.NextAction != NextRequestedHandlerAction.Poll) #endif Logger.LogSocketFlowMessage(ControllingHandler.saeaHandler, () => { return this.GetType().Name + " | " + "HandleCapturedSocketReset -> " + Enum.GetName(typeof(NextRequestedHandlerAction), _args_HandleCapturedSocketReset.NextAction) + (_args_HandleCapturedSocketReset.Count.HasValue ? " (Count = " + _args_HandleCapturedSocketReset.Count.Value.ToString() + ")" : ""); }); #endif #endregion ------------------------------------------------------------------------------------------------ CheckArgumentsCountProperty(_args_HandleCapturedSocketReset); ThreadPool.QueueUserWorkItem(PerformNextHandlerActionAsync, TranslateHandlerAction(_args_HandleCapturedSocketReset.NextAction)); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); return NextRequestedHandlerAction.Handled; } protected internal event EventHandler<MeasuredAmountEventArgs> OnMeasureBytesReceived; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, MeasuredAmountEventArgs, Task> OnMeasureBytesReceivedAsync; internal void TriggerOnMeasureBytesReceived(ulong amount) { var handler = OnMeasureBytesReceived; var asyncHandler = OnMeasureBytesReceivedAsync; if (handler == null && asyncHandler == null) { return; } if (_args_TriggerOnMeasureBytesReceived == null) { _args_TriggerOnMeasureBytesReceived = new MeasuredAmountEventArgs(amount); } else { _args_TriggerOnMeasureBytesReceived.Amount = amount; } if (handler != null) { handler(this, _args_TriggerOnMeasureBytesReceived); } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; await asyncHandler(this, _args_TriggerOnMeasureBytesReceived); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); } protected internal event EventHandler<MeasuredAmountEventArgs> OnMeasureBytesSend; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, MeasuredAmountEventArgs, Task> OnMeasureBytesSendAsync; internal void TriggerOnMeasureBytesSend(ulong amount) { var handler = OnMeasureBytesSend; var asyncHandler = OnMeasureBytesSendAsync; if (handler == null && asyncHandler == null) { return; } if (_args_TriggerOnMeasureBytesSend == null) { _args_TriggerOnMeasureBytesSend = new MeasuredAmountEventArgs(amount); } else { _args_TriggerOnMeasureBytesSend.Amount = amount; } if (handler != null) { handler(this, _args_TriggerOnMeasureBytesSend); } Task.Factory.StartNew(async delegate { try { bool sslStarted = this.SslStarted; await asyncHandler(this, _args_TriggerOnMeasureBytesSend); } catch (Exception e) { _HandleException(e); CloseAndReturnHandler(); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap(); } protected internal event EventHandler<HandleTransportSecurityInitInfoEventArgs> OnTransportSecurityInitiatationCompleted; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")] public event Func<object, HandleTransportSecurityInitInfoEventArgs, Task> OnTransportSecurityInitiatationCompletedAsync; internal void HandleTransportSecurityInitiatationCompleted() { #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogHandlerFlowMessage(saeaHandler, () => { var sb = new StringBuilder(); sb.Append(SslConversionStream.IsAuthenticated ? (SslConversionStream.IsServer ? "Transportsecurity successfully established" + (SslConversionStream.IsEncrypted ? "" : " WITHOUT encryption") + ", as server, " + (SslConversionStream.IsMutuallyAuthenticated ? "both parties are" : "client is") + " authenticated using certificates. " : "Transportsecurity successfully established" + (SslConversionStream.IsEncrypted ? "" : " WITHOUT encryption") + ", as client, " + (SslConversionStream.IsMutuallyAuthenticated ? "both parties are" : "server is") + " authenticated using certificates. " ) : (SslConversionStream.IsServer ? "Transportsecurity successfully estblished" + (SslConversionStream.IsEncrypted ? "" : " WITHOUT encryption") + ", as server without certificate authentication." : "Transportsecurity successfully estblished" + (SslConversionStream.IsEncrypted ? "" : " WITHOUT encryption") + ", as client without certificate authentication." ) ); if (SslConversionStream.IsSigned) { sb.Append("For tamper protection, data is being signed using a symmetric key algorithm. "); } sb.Append("A \"" + Enum.GetName(typeof(System.Security.Authentication.SslProtocols), SslConversionStream.SslProtocol) + "\" protocol is used using \"" + Enum.GetName(typeof(CipherAlgorithmType), SslConversionStream.CipherAlgorithm) + "\" cipher algorithm with a " + SslConversionStream.CipherStrength.ToString() + " bit cipher strength. " ); var name = Enum.GetName(typeof(ExchangeAlgorithmType), SslConversionStream.KeyExchangeAlgorithm); if (!String.IsNullOrWhiteSpace(name)) sb.Append("Key and protocol detail exchange was done using a \"" + name + "\" exchange algorithm, with a " + SslConversionStream.KeyExchangeStrength.ToString() + " bit key strength. " ); sb.Append("Using a \"" + Enum.GetName(typeof(HashAlgorithmType), SslConversionStream.HashAlgorithm) + "\" " + "hash algorithm, with a " + SslConversionStream.HashStrength.ToString() + " bit strength. " ); if (SslConversionStream.CheckCertRevocationStatus) { sb.Append("The remote certificate was checked for revocation, and was not revoked. "); } else { sb.Append("The remote certificate was NOT checked for revocation. "); } if (SslConversionStream.RemoteCertificate != null) { sb.Append("The remote \"" + SslConversionStream.RemoteCertificate.GetFormat() + "\" certificate was issued for " + "\"" + SslConversionStream.RemoteCertificate.Subject + "\" by " + "\"" + SslConversionStream.RemoteCertificate.Issuer + "\" " + "on " + SslConversionStream.RemoteCertificate.GetEffectiveDateString().Trim() + " and " + "will expire on " + SslConversionStream.RemoteCertificate.GetExpirationDateString() + " " + " and uses a \"" + SslConversionStream.RemoteCertificate.GetKeyAlgorithm() + "\" key algorithm." + " => " + SslConversionStream.RemoteCertificate.GetRawCertDataString() ); } return sb.ToString(); }); #endif #endregion ------------------------------------------------------------------------------------------------ var handler = OnTransportSecurityInitiatationCompleted; var asyncHandler = OnTransportSecurityInitiatationCompletedAsync; if (handler == null && asyncHandler == null) { return; } if (_args_HandleTransportSecurityInitiatationCompleted == null) { _args_HandleTransportSecurityInitiatationCompleted = new HandleTransportSecurityInitInfoEventArgs() { CheckCertRevocationStatus = SslConversionStream.CheckCertRevocationStatus, CipherAlgorithm = SslConversionStream.CipherAlgorithm, CipherStrength = SslConversionStream.CipherStrength, HashAlgorithm = SslConversionStream.HashAlgorithm, HashStrength = SslConversionStream.HashStrength, KeyExchangeAlgorithm = SslConversionStream.KeyExchangeAlgorithm, KeyExchangeStrength = SslConversionStream.KeyExchangeStrength, LocalCertificate = SslConversionStream.LocalCertificate, RemoteCertificate = SslConversionStream.RemoteCertificate, SslProtocol = SslConversionStream.SslProtocol, IsAuthenticatedByCertificate = SslConversionStream.IsAuthenticated, IsEncrypted = SslConversionStream.IsEncrypted, IsMutuallyAuthenticated = SslConversionStream.IsMutuallyAuthenticated, IsServer = SslConversionStream.IsServer, IsSigned = SslConversionStream.IsSigned }; } else { _args_HandleTransportSecurityInitiatationCompleted.CheckCertRevocationStatus = SslConversionStream.CheckCertRevocationStatus; _args_HandleTransportSecurityInitiatationCompleted.CipherAlgorithm = SslConversionStream.CipherAlgorithm; _args_HandleTransportSecurityInitiatationCompleted.CipherStrength = SslConversionStream.CipherStrength; _args_HandleTransportSecurityInitiatationCompleted.HashAlgorithm = SslConversionStream.HashAlgorithm; _args_HandleTransportSecurityInitiatationCompleted.HashStrength = SslConversionStream.HashStrength; _args_HandleTransportSecurityInitiatationCompleted.KeyExchangeAlgorithm = SslConversionStream.KeyExchangeAlgorithm; _args_HandleTransportSecurityInitiatationCompleted.KeyExchangeStrength = SslConversionStream.KeyExchangeStrength; _args_HandleTransportSecurityInitiatationCompleted.LocalCertificate = SslConversionStream.LocalCertificate; _args_HandleTransportSecurityInitiatationCompleted.RemoteCertificate = SslConversionStream.RemoteCertificate; _args_HandleTransportSecurityInitiatationCompleted.SslProtocol = SslConversionStream.SslProtocol; _args_HandleTransportSecurityInitiatationCompleted.IsAuthenticatedByCertificate = SslConversionStream.IsAuthenticated; _args_HandleTransportSecurityInitiatationCompleted.IsEncrypted = SslConversionStream.IsEncrypted; _args_HandleTransportSecurityInitiatationCompleted.IsMutuallyAuthenticated = SslConversionStream.IsMutuallyAuthenticated; _args_HandleTransportSecurityInitiatationCompleted.IsServer = SslConversionStream.IsServer; _args_HandleTransportSecurityInitiatationCompleted.IsSigned = SslConversionStream.IsSigned; } if (handler != null) { handler(this, _args_HandleTransportSecurityInitiatationCompleted); } } #endregion #region Misc void _HandleException(Exception e) { try { OnException(e); } catch { } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogException(e, this.GetType().Name + ": Exception occurred"); #endif #endregion ------------------------------------------------------------------------------------------------ } private HandleSocketEventArgs _args_HandleDisconnect; private HandleSocketBEventArgs _args_Uncaptured; private HandleSocketMessageEventArgs _args_OnNewMessage; private OnHandleExceptionEventArgs _args_OnHandleException; private HandleCapturedSocketBEventArg _args_Captured; private HandleCapturedSocketResetEventArgs _args_HandleCapturedSocketReset; private MeasuredAmountEventArgs _args_TriggerOnMeasureBytesReceived; private MeasuredAmountEventArgs _args_TriggerOnMeasureBytesSend; private HandleTransportSecurityInitInfoEventArgs _args_HandleTransportSecurityInitiatationCompleted; private HandleCapturedSocketEventArgs _args_CapturedDisconnect; private long _UniqueSocketId; protected internal void SetReceiveBuffer(int? MaxLength = null) { var l = MaxLength.HasValue ? MaxLength.Value : MemoryConfiguration.ReceiveBufferSize; if ((saeaHandler.Buffer == null) || (saeaHandler.Buffer.Length < l)) { saeaHandler.SetBuffer(new byte[l], 0, l); } else { saeaHandler.SetBuffer(0, l); } #region ---------------------------------------------------------------------------------------------[LOG]- #if (Logging) Logger.LogSocketFlowMessage(saeaHandler, () => { return "Setting receive size to " + saeaHandler.Count.ToString() + " bytes"; }); #endif #endregion ------------------------------------------------------------------------------------------------ } public void SetActivityTimestamp(bool CheckAutoResetTimeoutsFlag = false) { if ((!CheckAutoResetTimeoutsFlag) || (AutoResetTimeouts)) { Interlocked.Exchange(ref LastActivityTimeStamp, BitConverter.DoubleToInt64Bits(Timer.Duration)); } } public virtual void SetCurrentStageTimeoutSeconds(double TimeoutSeconds, bool AutoResetTimeouts = true, double? BeginActivityTimestamp = null) { Interlocked.Exchange(ref CurrentStageTimeout, BitConverter.DoubleToInt64Bits(TimeoutSeconds)); this.AutoResetTimeouts = AutoResetTimeouts; if (BeginActivityTimestamp.HasValue) { Interlocked.Exchange(ref LastActivityTimeStamp, BitConverter.DoubleToInt64Bits(BeginActivityTimestamp.Value)); } } #endregion #region System.Net.Socket /// <param name="keepaliveTime">Specifies the timeout, in milliseconds, with no activity until the first keep-alive packet is sent. The value must be greater than 0. If a value of less than or equal to zero is passed an ArgumentOutOfRangeException is thrown.</param> /// <param name="keepaliveInterval">Specifies the interval, in milliseconds, between when successive keep-alive packets are sent if no acknowledgement is received. The value must be greater than 0. If a value of less than or equal to zero is passed an ArgumentOutOfRangeException is thrown.</param> protected void SetTcpKeepAlive(uint keepaliveTime, uint keepaliveInterval) { SocketIO.SetTcpKeepAlive(saeaHandler, keepaliveTime, keepaliveInterval); } protected void SetReceiveBufferSize(int size) { SocketIO.SetReceiveBufferSize(saeaHandler, size); } protected void SetSendBufferSize(int size) { SocketIO.SetSendBufferSize(saeaHandler, size); } protected void SetBlocking(bool blocking) { SocketIO.SetBlocking(saeaHandler, blocking); } protected void SetNoDelay(bool nodelay) { SocketIO.SetNoDelay(saeaHandler, nodelay); } void CheckArgumentsCountProperty(HandleSocketBEventArgs eventArgs) { if (saeaHandler == null) return; switch (eventArgs.NextAction) { case NextRequestedHandlerAction.Receive: if (eventArgs.Count.HasValue) receiveCount = eventArgs.Count.Value; else if (SslStarted) receiveCount = 1; if (!SslStarted) { SetReceiveBuffer(); } break; } } void CheckArgumentsCountProperty(HandleCapturedSocketBEventArg eventArgs) { var handler = eventArgs.saeaCapture.Handler().ControllingHandler; var sslStarted = handler.SslStarted; switch (eventArgs.NextAction) { case NextRequestedCapturedHandlerAction.Receive: if (eventArgs.Count.HasValue) receiveCount = eventArgs.Count.Value; else { if (sslStarted) { handler.receiveCount = 1; } } if (!sslStarted) { handler.SetReceiveBuffer(); } break; } } #endregion #region SocketHandlerAction enum /// <summary> /// Determines what next internal action is needed /// </summary> internal enum SocketHandlerActions { None, Initialize, Connect, AsyncAction, Receive, Send, StopTransportSecurity, Disconnect, Poll, WaitForSignal, WaitForMessage, ProcessReceivedMessage, Dispose, SetIdle, Handled, ReleaseControl, CaptureReleased, CaptureAccquired, CapturedReceive, CapturedSend, CapturedDisconnect, CaptureReleaseRequest, CaptureReleasedUnRequested, DisposeCapturingHandler }; #endregion } #region Public Enums /// <summary> /// Determines the next asynchronous handler action that should be started /// </summary> public enum NextRequestedHandlerAction { Connect, AsyncAction, Receive, Send, StopTransportSecurity, Disconnect, WaitForSignal, Poll, WaitForMessage, Dispose, SetIdle, Handled, ReleaseControl }; /// <summary> /// Determines the next asynchronous handler action that should be started /// </summary> public enum NextRequestedCapturedHandlerAction { Receive, Send, Disconnect, Release, DisposeCapturedHandler, DisposeCapturingHandler, Handled }; #endregion } |