/// <summary> /// Accepts incoming connections. /// </summary> public void AcceptConnections() { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; byte protocolVersion; GenuineConnectionType genuineConnectionType; try { IParameterProvider parameters = this.ITransportContext.IParameterProvider; string mutexName = GenuineSharedMemoryChannel.ConstructSharedObjectName( "MUTEX" + this.ShareName, parameters); string clientConnected = GenuineSharedMemoryChannel.ConstructSharedObjectName( "CC" + this.ShareName, parameters); string clientAccepted = GenuineSharedMemoryChannel.ConstructSharedObjectName( "CA" + this.ShareName, parameters); this._mutex = WindowsAPI.CreateMutex(mutexName); this._clientConnectedEvent = NamedEvent.CreateNamedEvent(clientConnected, false, false); this._clientAcceptedEvent = NamedEvent.CreateNamedEvent(clientAccepted, false, true); WaitHandle[] handles = new WaitHandle[2] { this._clientConnectedEvent.ManualResetEvent, this.StopListening }; for ( ; ;) { try { // listen WaitHandle.WaitAny(handles); // if shutting down if (this.StopListening.WaitOne(0, false)) { return; } // set timeout int timeout = GenuineUtility.GetTimeout((TimeSpan)this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]); // client is connecting using (Stream headerStream = this.SharedMemoryConnection.LowLevel_ReadSync(timeout)) { BinaryReader binaryReader = new BinaryReader(headerStream); string connectionId; MessageCoder.DeserializeConnectionHeader(binaryReader, out protocolVersion, out genuineConnectionType, out connectionId); string shareName = binaryReader.ReadString(); this._clientAcceptedEvent.ManualResetEvent.Set(); // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0) { binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "SMAcceptConnectionClosure.AcceptConnections", LogMessageType.ConnectionAccepting, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, 0, 0, 0, null, null, null, null, "An inbound Shared Memory connection is being accepted."); } AcceptConnectionInformation acceptConnectionInformation = new AcceptConnectionInformation(); acceptConnectionInformation.ShareName = shareName; acceptConnectionInformation.ProtocolVersion = protocolVersion; GenuineThreadPool.QueueUserWorkItem(new WaitCallback(this.AcceptConnection), acceptConnectionInformation, true); } } catch (Exception ex) { // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0) { binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "SMAcceptConnectionClosure.AcceptConnections", LogMessageType.ConnectionAccepting, ex, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, 0, 0, 0, null, null, null, null, "Can't accept a connection."); } } } } catch (Exception ex) { // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0) { binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "SMAcceptConnectionClosure.AcceptConnections", LogMessageType.CriticalError, ex, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, 0, 0, 0, null, null, null, null, "Critical listener failure. No connections will be accepted."); } this.SharedMemoryConnectionManager.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(GenuineEventType.GeneralListenerFailure, ex, null, this.ShareName)); } finally { this.SharedMemoryConnection.ReleaseUnmanagedResources(); if (this._mutex != null) { this._mutex.Close(); } } }
/// <summary> /// Constructs an instance of the SharedMemoryConnection class. /// </summary> /// <param name="iTransportContext">The transport context.</param> /// <param name="name">The name of the shared chunk.</param> /// <param name="isServer">The role.</param> /// <param name="setCloseStatusOnExit">Indicates whether it is necessary to set the "closed" status on exit.</param> internal SharedMemoryConnection(ITransportContext iTransportContext, string name, bool isServer, bool setCloseStatusOnExit) { this.ITransportContext = iTransportContext; this.ShareName = "GenuineChannels_GShMem_" + name; this.IsServer = isServer; this._setCloseStatusOnExit = setCloseStatusOnExit; this._shareSize = (int)iTransportContext.IParameterProvider[GenuineParameter.SMShareSize]; this._pingTimeOut = GenuineUtility.ConvertToMilliseconds(iTransportContext.IParameterProvider[GenuineParameter.PersistentConnectionSendPingAfterInactivity]); this._closeAfterInactivity = GenuineUtility.ConvertToMilliseconds(iTransportContext.IParameterProvider[GenuineParameter.ClosePersistentConnectionAfterInactivity]); string localSideName = (isServer ? "Server" : "Client"); string remoteSideName = (isServer ? "Client" : "Server"); IParameterProvider parameters = this.ITransportContext.IParameterProvider; // construct shared object names for the local side string readCompletedEventName = GenuineSharedMemoryChannel.ConstructSharedObjectName( this.ShareName + localSideName + "ReadCompleted", parameters); string writeCompletedEventName = GenuineSharedMemoryChannel.ConstructSharedObjectName( this.ShareName + localSideName + "WriteCompleted", parameters); // construct shared object names for the remote side string remoteReadCompletedEventName = GenuineSharedMemoryChannel.ConstructSharedObjectName( this.ShareName + remoteSideName + "ReadCompleted", parameters); string remoteWriteCompletedEventName = GenuineSharedMemoryChannel.ConstructSharedObjectName( this.ShareName + remoteSideName + "WriteCompleted", parameters); if (isServer) { if (this._shareSize < MIN_SHARE_SIZE || this._shareSize > MAX_SHARE_SIZE) { throw GenuineExceptions.Get_Channel_InvalidParameter("SMShareSize"); } this.LowLevel_CreateSharedMemory(); this._closed = 0; this._writtenShareSize = this._shareSize; this._receiveOffset = 5; this._sendOffset = (this._shareSize - 5) / 2; this._receiveSpaceSize = this._sendOffset - 5 - 8; this._sendSpaceSize = this._shareSize - this._sendOffset - 8; this._namedEventReadCompleted = NamedEvent.CreateNamedEvent(readCompletedEventName, false, true); this._namedEventWriteCompleted = NamedEvent.CreateNamedEvent(writeCompletedEventName, false, true); this._namedEventRemoteReadCompleted = NamedEvent.CreateNamedEvent(remoteReadCompletedEventName, false, true); this._namedEventRemoteWriteCompleted = NamedEvent.CreateNamedEvent(remoteWriteCompletedEventName, false, true); } else { this.OpenSharedMemory(); if (this._closed != 0) { throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(name, "Remote host has already closed the connection."); } this._shareSize = this._writtenShareSize; if (this._shareSize < MIN_SHARE_SIZE || this._shareSize > MAX_SHARE_SIZE) { throw GenuineExceptions.Get_Channel_InvalidParameter("SMShareSize"); } this._receiveOffset = (this._shareSize - 5) / 2; this._sendOffset = 5; this._receiveSpaceSize = this._shareSize - this._receiveOffset - 8; this._sendSpaceSize = this._receiveOffset - 5 - 8; this._namedEventReadCompleted = NamedEvent.OpenNamedEvent(readCompletedEventName); this._namedEventWriteCompleted = NamedEvent.OpenNamedEvent(writeCompletedEventName); this._namedEventRemoteReadCompleted = NamedEvent.OpenNamedEvent(remoteReadCompletedEventName); this._namedEventRemoteWriteCompleted = NamedEvent.OpenNamedEvent(remoteWriteCompletedEventName); } this._sendBuffer = new byte[this._sendSpaceSize]; }
/// <summary> /// Accepts incoming connections. /// </summary> public void AcceptConnections() { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; byte protocolVersion; GenuineConnectionType genuineConnectionType; try { IParameterProvider parameters = this.ITransportContext.IParameterProvider; string mutexName = GenuineSharedMemoryChannel.ConstructSharedObjectName( "MUTEX" + this.ShareName, parameters); string clientConnected = GenuineSharedMemoryChannel.ConstructSharedObjectName( "CC" + this.ShareName, parameters); string clientAccepted = GenuineSharedMemoryChannel.ConstructSharedObjectName( "CA" + this.ShareName, parameters); this._mutex = WindowsAPI.CreateMutex(mutexName); this._clientConnectedEvent = NamedEvent.CreateNamedEvent(clientConnected, false, false); this._clientAcceptedEvent = NamedEvent.CreateNamedEvent(clientAccepted, false, true); WaitHandle[] handles = new WaitHandle[2] { this._clientConnectedEvent.ManualResetEvent, this.StopListening }; for ( ; ; ) { try { // listen WaitHandle.WaitAny(handles); // if shutting down if (this.StopListening.WaitOne(0, false)) return ; // set timeout int timeout = GenuineUtility.GetTimeout((TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]); // client is connecting using (Stream headerStream = this.SharedMemoryConnection.LowLevel_ReadSync(timeout)) { BinaryReader binaryReader = new BinaryReader(headerStream); string connectionId; MessageCoder.DeserializeConnectionHeader(binaryReader, out protocolVersion, out genuineConnectionType, out connectionId); string shareName = binaryReader.ReadString(); this._clientAcceptedEvent.ManualResetEvent.Set(); // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "SMAcceptConnectionClosure.AcceptConnections", LogMessageType.ConnectionAccepting, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, 0, 0, 0, null, null, null, null, "An inbound Shared Memory connection is being accepted."); } AcceptConnectionInformation acceptConnectionInformation = new AcceptConnectionInformation(); acceptConnectionInformation.ShareName = shareName; acceptConnectionInformation.ProtocolVersion = protocolVersion; GenuineThreadPool.QueueUserWorkItem(new WaitCallback(this.AcceptConnection), acceptConnectionInformation, true); } } catch(Exception ex) { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "SMAcceptConnectionClosure.AcceptConnections", LogMessageType.ConnectionAccepting, ex, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, 0, 0, 0, null, null, null, null, "Can't accept a connection."); } } } } catch(Exception ex) { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "SMAcceptConnectionClosure.AcceptConnections", LogMessageType.CriticalError, ex, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, 0, 0, 0, null, null, null, null, "Critical listener failure. No connections will be accepted."); } this.SharedMemoryConnectionManager.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(GenuineEventType.GeneralListenerFailure, ex, null, this.ShareName)); } finally { this.SharedMemoryConnection.ReleaseUnmanagedResources(); if (this._mutex != null) this._mutex.Close(); } }
/// <summary> /// Opens a connection to the host specified by the url. /// </summary> /// <param name="remote">The HostInformation of the Remote Host.</param> /// <param name="localUri">The uri of the local host.</param> /// <param name="remoteUri">The uri of the remote host.</param> /// <param name="remoteHostUniqueIdentifier">The unique identifier of the HostInformation used by the remote host.</param> /// <returns>The established connection.</returns> private SharedMemoryConnection LowLevel_OpenConnection(HostInformation remote, string localUri, out string remoteUri, out int remoteHostUniqueIdentifier) { using (new ReaderAutoLocker(this._disposeLock)) { if (this._disposed) { throw OperationException.WrapException(this._disposeReason); } } remoteUri = null; Stream inputStream = null; Stream outputStream = null; string url = remote.Url; // the maximum time during which the connection must be established int timeout = GenuineUtility.GetTimeout((TimeSpan)this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]); IParameterProvider parameters = this.ITransportContext.IParameterProvider; string mutexName = GenuineSharedMemoryChannel.ConstructSharedObjectName( "MUTEX" + url, parameters); string clientConnected = GenuineSharedMemoryChannel.ConstructSharedObjectName( "CC" + url, parameters); string clientAccepted = GenuineSharedMemoryChannel.ConstructSharedObjectName( "CA" + url, parameters); // open the server share SharedMemoryConnection serverSharedMemoryConnection = new SharedMemoryConnection(this.ITransportContext, url, false, false); // LOG: BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0) { binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_OpenConnection", LogMessageType.ConnectionParameters, null, remote, this.ITransportContext.IParameterProvider, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, serverSharedMemoryConnection.DbgConnectionId, "A Shared Memory connection is being established."); } // and create the local share string shareName = "gshmem://" + Guid.NewGuid().ToString("N"); SharedMemoryConnection sharedMemoryConnection = new SharedMemoryConnection(this.ITransportContext, shareName, true, true); BinaryWriter connectionInformation = MessageCoder.SerializeConnectionHeader(MessageCoder.PROTOCOL_VERSION, GenuineConnectionType.Persistent, "Default"); connectionInformation.Write(shareName); // let the server know that a client's share is ready Mutex mutex = null; try { mutex = WindowsAPI.OpenMutex(mutexName); NamedEvent _clientConnected = NamedEvent.OpenNamedEvent(clientConnected); NamedEvent _clientAccepted = NamedEvent.OpenNamedEvent(clientAccepted); if (!GenuineUtility.WaitOne(mutex, GenuineUtility.GetMillisecondsLeft(timeout))) { throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Can not acquire the lock for the global mutex."); } // wait until server accepts this client _clientAccepted.ManualResetEvent.Reset(); _clientConnected.ManualResetEvent.Set(); // copy client's name serverSharedMemoryConnection.LowLevel_SendSync(connectionInformation.BaseStream, timeout); if (!GenuineUtility.WaitOne(_clientAccepted.ManualResetEvent, GenuineUtility.GetMillisecondsLeft(timeout))) { throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Remote server did not accept a request within the specified time span."); } } finally { if (mutex != null) { try { mutex.ReleaseMutex(); } catch { } try { mutex.Close(); } catch { } } } // get the connection-level Security Session string connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string; SecuritySession securitySession = null; if (connectionLevelSSName != null) { securitySession = this.ITransportContext.IKeyStore.GetKey(connectionLevelSSName).CreateSecuritySession(connectionLevelSSName, null); } // establish it if (securitySession != null && !securitySession.IsEstablished) { bool firstPass = true; for ( ; ;) { inputStream = Stream.Null; try { // prepare streams if (!firstPass) { inputStream = sharedMemoryConnection.LowLevel_ReadSync(timeout); } else { firstPass = false; } outputStream = securitySession.EstablishSession(inputStream, true); if (outputStream == null) { break; } // send a packet to the remote host sharedMemoryConnection.LowLevel_SendSync(outputStream, timeout); if (securitySession.IsEstablished) { break; } } finally { if (inputStream != null) { inputStream.Close(); } if (outputStream != null) { outputStream.Close(); } } } } sharedMemoryConnection.ConnectionLevelSecurity = securitySession; // now send connection info through the established connection using (GenuineChunkedStream serializedLocalInfo = new GenuineChunkedStream(false)) { // serialize local info BinaryWriter binaryWriter = new BinaryWriter(serializedLocalInfo); binaryWriter.Write((string)localUri); binaryWriter.Write((int)remote.LocalHostUniqueIdentifier); // and send it sharedMemoryConnection.LowLevel_SendSync(serializedLocalInfo, timeout); // read remote info using (Stream remoteUriStream = sharedMemoryConnection.LowLevel_ReadSync(timeout)) { BinaryReader binaryReader = new BinaryReader(remoteUriStream); remoteUri = binaryReader.ReadString(); remoteHostUniqueIdentifier = binaryReader.ReadInt32(); } } sharedMemoryConnection.Remote = remote; sharedMemoryConnection.Remote.UpdateUri(remoteUri, remoteHostUniqueIdentifier); sharedMemoryConnection.Remote.GenuinePersistentConnectionState = GenuinePersistentConnectionState.Opened; // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.HostInformation] > 0) { binaryLogWriter.WriteHostInformationEvent("SharedMemoryConnectionManager.LowLevel_OpenConnection", LogMessageType.HostInformationCreated, null, remote, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, sharedMemoryConnection.DbgConnectionId, "HostInformation is ready for actions."); } // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0) { binaryLogWriter.WriteEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_OpenConnection", LogMessageType.ConnectionEstablished, null, null, remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, securitySession, connectionLevelSSName, sharedMemoryConnection.DbgConnectionId, (int)GenuineConnectionType.Persistent, 0, 0, this.GetType().Name, null, null, null, "The connection to the remote host is established."); } return(sharedMemoryConnection); }
/// <summary> /// Constructs an instance of the SharedMemoryConnection class. /// </summary> /// <param name="iTransportContext">The transport context.</param> /// <param name="name">The name of the shared chunk.</param> /// <param name="isServer">The role.</param> /// <param name="setCloseStatusOnExit">Indicates whether it is necessary to set the "closed" status on exit.</param> internal SharedMemoryConnection(ITransportContext iTransportContext, string name, bool isServer, bool setCloseStatusOnExit) { this.ITransportContext = iTransportContext; this.ShareName = "GenuineChannels_GShMem_" + name; this.IsServer = isServer; this._setCloseStatusOnExit = setCloseStatusOnExit; this._shareSize = (int) iTransportContext.IParameterProvider[GenuineParameter.SMShareSize]; this._pingTimeOut = GenuineUtility.ConvertToMilliseconds(iTransportContext.IParameterProvider[GenuineParameter.PersistentConnectionSendPingAfterInactivity]); this._closeAfterInactivity = GenuineUtility.ConvertToMilliseconds(iTransportContext.IParameterProvider[GenuineParameter.ClosePersistentConnectionAfterInactivity]); string localSideName = (isServer ? "Server" : "Client"); string remoteSideName = (isServer ? "Client" : "Server"); IParameterProvider parameters = this.ITransportContext.IParameterProvider; // construct shared object names for the local side string readCompletedEventName = GenuineSharedMemoryChannel.ConstructSharedObjectName( this.ShareName + localSideName + "ReadCompleted", parameters); string writeCompletedEventName = GenuineSharedMemoryChannel.ConstructSharedObjectName( this.ShareName + localSideName + "WriteCompleted", parameters); // construct shared object names for the remote side string remoteReadCompletedEventName = GenuineSharedMemoryChannel.ConstructSharedObjectName( this.ShareName + remoteSideName + "ReadCompleted", parameters); string remoteWriteCompletedEventName = GenuineSharedMemoryChannel.ConstructSharedObjectName( this.ShareName + remoteSideName + "WriteCompleted", parameters); if (isServer) { if (this._shareSize < MIN_SHARE_SIZE || this._shareSize > MAX_SHARE_SIZE) throw GenuineExceptions.Get_Channel_InvalidParameter("SMShareSize"); this.LowLevel_CreateSharedMemory(); this._closed = 0; this._writtenShareSize = this._shareSize; this._receiveOffset = 5; this._sendOffset = (this._shareSize - 5) / 2; this._receiveSpaceSize = this._sendOffset - 5 - 8; this._sendSpaceSize = this._shareSize - this._sendOffset - 8; this._namedEventReadCompleted = NamedEvent.CreateNamedEvent(readCompletedEventName, false, true); this._namedEventWriteCompleted = NamedEvent.CreateNamedEvent(writeCompletedEventName, false, true); this._namedEventRemoteReadCompleted = NamedEvent.CreateNamedEvent(remoteReadCompletedEventName, false, true); this._namedEventRemoteWriteCompleted = NamedEvent.CreateNamedEvent(remoteWriteCompletedEventName, false, true); } else { this.OpenSharedMemory(); if (this._closed != 0) throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(name, "Remote host has already closed the connection."); this._shareSize = this._writtenShareSize; if (this._shareSize < MIN_SHARE_SIZE || this._shareSize > MAX_SHARE_SIZE) throw GenuineExceptions.Get_Channel_InvalidParameter("SMShareSize"); this._receiveOffset = (this._shareSize - 5) / 2; this._sendOffset = 5; this._receiveSpaceSize = this._shareSize - this._receiveOffset - 8; this._sendSpaceSize = this._receiveOffset - 5 - 8; this._namedEventReadCompleted = NamedEvent.OpenNamedEvent(readCompletedEventName); this._namedEventWriteCompleted = NamedEvent.OpenNamedEvent(writeCompletedEventName); this._namedEventRemoteReadCompleted = NamedEvent.OpenNamedEvent(remoteReadCompletedEventName); this._namedEventRemoteWriteCompleted = NamedEvent.OpenNamedEvent(remoteWriteCompletedEventName); } this._sendBuffer = new byte[this._sendSpaceSize]; }